1  /-
  2  Copyright (c) 2018 Mario Carneiro. All rights reserved.
  3  Released under Apache 2.0 license as described in the file LICENSE.
  4  Author: Mario Carneiro
  5  
  6  The primitive recursive functions are the least collection of functions
  7  nat → nat which are closed under projections (using the mkpair
  8  pairing function), composition, zero, successor, and primitive recursion
  9  (i.e. nat.rec where the motive is C n := nat).
 10  
 11  We can extend this definition to a large class of basic types by
 12  using canonical encodings of types as natural numbers (Gödel numbering),
 13  which we implement through the type class `encodable`. (More precisely,
 14  we need that the composition of encode with decode yields a
 15  primitive recursive function, so we have the `primcodable` type class
 16  for this.)
 17  -/
 18  import data.equiv.list
src         └─────────────┘
 19  
 20  open denumerable encodable
 21  
 22  namespace nat
 23  
 24  def elim {C : Sort*} : C → (ℕ → C → C) → ℕ → C := @nat.rec (λ _, C)
id                                               └─────┘      
src                                                   └─────┘
typ                                              └─────┘      
 25  
 26  @[simp] theorem elim_zero {C} (a f) : @nat.elim C a f 0 = a := rfl
id                                          └──────┘           └─┘
src                                         └──────┘               └─┘
typ                                         └──────┘           └─┘
doc    └──┘
 27  @[simp] theorem elim_succ {C} (a f n) :
doc    └──┘
 28    @nat.elim C a f (succ n) = f n (nat.elim a f n) := rfl
id      └──────┘     └──┘       └──────┘        └─┘
src     └──────┘        └──┘          └──────┘           └─┘
typ     └──────┘     └──┘       └──────┘        └─┘
 29  
 30  def cases {C : Sort*} (a : C) (f : ℕ → C) : ℕ → C := nat.elim a (λ n _, f n)
id                                                   └──────┘         
src                                                     └──────┘
typ                                                  └──────┘         
 31  
 32  @[simp] theorem cases_zero {C} (a f) : @nat.cases C a f 0 = a := rfl
id                                           └───────┘           └─┘
src                                          └───────┘               └─┘
typ                                          └───────┘           └─┘
doc    └──┘
 33  @[simp] theorem cases_succ {C} (a f n) : @nat.cases C a f (succ n) = f n := rfl
id                                             └───────┘     └──┘         └─┘
src                                            └───────┘        └──┘            └─┘
typ                                            └───────┘     └──┘         └─┘
doc    └──┘
 34  
 35  @[simp, reducible] def unpaired {α} (f : ℕ → ℕ → α) (n : ℕ) : α :=
id                                                             
src                                                         
typ                                                            
doc    └──┘  └───────┘
 36  f n.unpair.1 n.unpair.2
id    └─────┘  └─────┘
src     └─────┘   └─────┘
typ   └─────┘  └─────┘
doc     └─────┘    └─────┘
 37  
 38  /-- The primitive recursive functions `ℕ → ℕ`. -/
 39  inductive primrec : (ℕ → ℕ) → Prop
id                          
src                          
typ                         
 40  | zero : primrec (λ n, 0)
id                       
typ                      
 41  | succ : primrec succ
id                    └──┘
src                   └──┘
typ                   └──┘
 42  | left : primrec (λ n, n.unpair.1)
id                         └─────┘
src                          └─────┘
typ                        └─────┘
doc                          └─────┘
 43  | right : primrec (λ n, n.unpair.2)
id                          └─────┘
src                           └─────┘
typ                         └─────┘
doc                           └─────┘
 44  | pair {f g} : primrec f → primrec g → primrec (λ n, mkpair (f n) (g n))
id                └─────┘    └─────┘                 └────┘       
src                                                       └────┘
typ               └─────┘    └─────┘                 └────┘       
doc                                                       └────┘
 45  | comp {f g} : primrec f → primrec g → primrec (λ n, f (g n))
id                └─────┘    └─────┘                    
typ               └─────┘    └─────┘                    
 46  | prec {f g} : primrec f → primrec g → primrec (unpaired (λ z n,
id                └─────┘    └─────┘             └──────┘     
src                                                  └──────┘
typ               └─────┘    └─────┘             └──────┘     
 47     n.elim (f z) (λ y IH, g $ mkpair z $ mkpair y IH)))
id      └───┘         └┘     └────┘    └────┘  └┘
src      └───┘                    └────┘     └────┘
typ     └───┘         └┘     └────┘    └────┘  └┘
doc                               └────┘     └────┘
 48  
 49  namespace primrec
 50  
 51  theorem of_eq {f g : ℕ → ℕ} (hf : primrec f) (H : ∀ n, f n = g n) : primrec g :=
id                                   └─────┘                    └─────┘ 
src                                  └─────┘                          └─────┘
typ                                  └─────┘                    └─────┘ 
doc                                    └─────┘                           └─────┘
 52  (funext H : f = g) ▸ hf
id    └────┘         └┘
src   └────┘           
typ   └────┘         └┘
 53  
 54  theorem const : ∀ (n : ℕ), primrec (λ _, n)
id                            └─────┘      
src                            └─────┘
typ                           └─────┘      
doc                             └─────┘
 55  | 0 := zero
id          └──┘
src         └──┘
typ         └──┘
 56  | (n+1) := succ.comp (const n)
id            └──┘└───┘  └───┘
src            └───────┘
typ           └──┘└───┘  └───┘
 57  
 58  protected theorem id : primrec id :=
id                          └─────┘ └┘
src                         └─────┘ └┘
typ                         └─────┘ └┘
doc                         └─────┘
 59  (left.pair right).of_eq $ λ n, by simp
id    └──┘└───┘ └───┘ └───┘      
src   └───────┘ └───┘ └───┘            └────
typ   └──┘└───┘ └───┘ └───┘           └────
doc                                    └────
txt                                    └────
par                                    └────
pid                                        
st                                    └─────
 60  
src  
typ  
doc  
txt  
par  
pid  
st   
 61  theorem prec1 {f} (m : ℕ) (hf : primrec f) : primrec (λ n,
id                                  └─────┘     └─────┘    
src                                 └─────┘      └─────┘
typ                                 └─────┘     └─────┘    
doc                                  └─────┘      └─────┘
 62     n.elim m (λ y IH, f $ mkpair y IH)) :=
id      └───┘      └┘     └────┘  └┘
src      └───┘                └────┘
typ     └───┘      └┘     └────┘  └┘
doc                           └────┘
 63  ((prec (const m) (hf.comp right)).comp
id     └──┘  └───┘    └┘└───┘ └───┘  └──┘
src    └──┘  └───┘       └───┘ └───┘  └──┘
typ    └──┘  └───┘    └┘└───┘ └───┘  └──┘
 64    (zero.pair primrec.id)).of_eq $
id      └──┘└───┘ └────────┘  └───┘
src     └───────┘ └────────┘  └───┘
typ     └──┘└───┘ └────────┘  └───┘
 65  λ n, by simp; dsimp; rw [unpair_mkpair]
id     
src          └──┘  └───┘  └──┘             └─
typ         └──┘  └───┘  └──┘             └─
doc          └──┘  └───┘  └──┘             └─
txt          └──┘  └───┘  └──┘             └─
par          └──┘  └───┘  └──┘             └─
pid                         └┘             
st          └────────────────┘              
 66  
src  
typ  
doc  
txt  
par  
pid  
st   
 67  theorem cases1 {f} (m : ℕ) (hf : primrec f) : primrec (nat.cases m f) :=
id                                   └─────┘     └─────┘  └───────┘  
src                                  └─────┘      └─────┘  └───────┘
typ                                  └─────┘     └─────┘  └───────┘  
doc                                   └─────┘      └─────┘
 68  (prec1 m (hf.comp left)).of_eq $ by simp [cases]
id    └───┘   └┘└───┘ └──┘  └───┘             └───┘
src   └───┘      └───┘ └──┘  └───┘       └────┘└───┘└─
typ   └───┘   └┘└───┘ └──┘  └───┘       └────┘└───┘└─
doc                                      └────┘     └─
txt                                      └────┘     └─
par                                      └────┘     └─
pid                                               
st                                      └─────────────
 69  
src  
typ  
doc  
txt  
par  
pid  
st   
 70  theorem cases {f g} (hf : primrec f) (hg : primrec g) :
id                             └─────┘         └─────┘ 
src                            └─────┘          └─────┘
typ                            └─────┘         └─────┘ 
doc                            └─────┘          └─────┘
 71    primrec (unpaired (λ z n, n.cases (f z) (λ y, g $ mkpair z y))) :=
id     └─────┘  └──────┘       └────┘             └────┘  
src    └─────┘  └──────┘          └────┘                 └────┘
typ    └─────┘  └──────┘       └────┘             └────┘  
doc    └─────┘                                           └────┘
 72  (prec hf (hg.comp (pair left (left.comp right)))).of_eq $ by simp [cases]
id    └──┘ └┘  └┘└───┘  └──┘ └──┘  └──┘└───┘ └───┘    └───┘             └───┘
src   └──┘       └───┘  └──┘ └──┘  └───────┘ └───┘    └───┘       └────┘└───┘└─
typ   └──┘ └┘  └┘└───┘  └──┘ └──┘  └──┘└───┘ └───┘    └───┘       └────┘└───┘└─
doc                                                               └────┘     └─
txt                                                               └────┘     └─
par                                                               └────┘     └─
pid                                                                        
st                                                               └─────────────
 73  
src  
typ  
doc  
txt  
par  
pid  
st   
 74  protected theorem swap : primrec (unpaired (function.swap mkpair)) :=
id                            └─────┘  └──────┘  └───────────┘ └────┘
src                           └─────┘  └──────┘  └───────────┘ └────┘
typ                           └─────┘  └──────┘  └───────────┘ └────┘
doc                           └─────┘                          └────┘
 75  (pair right left).of_eq $ λ n, by simp
id    └──┘ └───┘ └──┘ └───┘      
src   └──┘ └───┘ └──┘ └───┘            └────
typ   └──┘ └───┘ └──┘ └───┘           └────
doc                                    └────
txt                                    └────
par                                    └────
pid                                        
st                                    └─────
 76  
src  
typ  
doc  
txt  
par  
pid  
st   
 77  theorem swap' {f} (hf : primrec (unpaired f)) : primrec (unpaired (function.swap f)) :=
id                           └─────┘  └──────┘      └─────┘  └──────┘  └───────────┘ 
src                          └─────┘  └──────┘       └─────┘  └──────┘  └───────────┘
typ                          └─────┘  └──────┘      └─────┘  └──────┘  └───────────┘ 
doc                          └─────┘                 └─────┘
 78  (hf.comp primrec.swap).of_eq $ λ n, by simp
id    └┘└───┘ └──────────┘ └───┘      
src     └───┘ └──────────┘ └───┘            └────
typ   └┘└───┘ └──────────┘ └───┘           └────
doc                                         └────
txt                                         └────
par                                         └────
pid                                             
st                                         └─────
 79  
src  
typ  
doc  
txt  
par  
pid  
st   
 80  theorem pred : primrec pred :=
id                  └─────┘ └──┘
src                 └─────┘ └──┘
typ                 └─────┘ └──┘
doc                 └─────┘
 81  (cases1 0 primrec.id).of_eq $ λ n, by cases n; simp *
id    └────┘   └────────┘ └───┘                 
src   └────┘   └────────┘ └───┘            └────┘   └──────
typ   └────┘   └────────┘ └───┘           └────┘  └──────
doc                                        └────┘   └──────
txt                                        └────┘   └──────
par                                        └────┘   └──────
pid                                                    
st                                        └────────────────
 82  
src  
typ  
doc  
txt  
par  
pid  
st   
 83  theorem add : primrec (unpaired (+)) :=
id                 └─────┘  └──────┘ 
src                └─────┘  └──────┘ 
typ                └─────┘  └──────┘ 
doc                └─────┘
 84  (prec primrec.id ((succ.comp right).comp right)).of_eq $
id    └──┘ └────────┘   └──┘└───┘ └───┘ └──┘  └───┘  └───┘
src   └──┘ └────────┘   └───────┘ └───┘ └──┘  └───┘  └───┘
typ   └──┘ └────────┘   └──┘└───┘ └───┘ └──┘  └───┘  └───┘
 85  λ p, by simp; induction p.unpair.2; simp [*, -add_comm, add_succ]
id                          └──────┘                        └──────┘
src          └──┘  └────────┘└──────┘└┘  └──────────────────┘└──────┘└─
typ         └──┘  └────────┘└──────┘└┘  └──────────────────┘└──────┘└─
doc          └──┘  └────────┘└──────┘└┘  └──────────────────┘        └─
txt          └──┘  └────────┘        └┘  └──────────────────┘        └─
par          └──┘  └────────┘        └┘  └──────────────────┘        └─
pid                                 └┘      └─────────────┘        
st          └──────────────────────────────────────────────────────────
 86  
src  
typ  
doc  
txt  
par  
pid  
st   
 87  theorem sub : primrec (unpaired has_sub.sub) :=
id                 └─────┘  └──────┘ └─────────┘
src                └─────┘  └──────┘ └─────────┘
typ                └─────┘  └──────┘ └─────────┘
doc                └─────┘
 88  (prec primrec.id ((pred.comp right).comp right)).of_eq $
id    └──┘ └────────┘   └──┘└───┘ └───┘ └──┘  └───┘  └───┘
src   └──┘ └────────┘   └──┘└───┘ └───┘ └──┘  └───┘  └───┘
typ   └──┘ └────────┘   └──┘└───┘ └───┘ └──┘  └───┘  └───┘
 89  λ p, by simp; induction p.unpair.2; simp [*, -add_comm, sub_succ]
id                          └──────┘                        └──────┘
src          └──┘  └────────┘└──────┘└┘  └──────────────────┘└──────┘└─
typ         └──┘  └────────┘└──────┘└┘  └──────────────────┘└──────┘└─
doc          └──┘  └────────┘└──────┘└┘  └──────────────────┘        └─
txt          └──┘  └────────┘        └┘  └──────────────────┘        └─
par          └──┘  └────────┘        └┘  └──────────────────┘        └─
pid                                 └┘      └─────────────┘        
st          └──────────────────────────────────────────────────────────
 90  
src  
typ  
doc  
txt  
par  
pid  
st   
 91  theorem mul : primrec (unpaired (*)) :=
id                 └─────┘  └──────┘ 
src                └─────┘  └──────┘ 
typ                └─────┘  └──────┘ 
doc                └─────┘
 92  (prec zero (add.comp (pair left (right.comp right)))).of_eq $
id    └──┘ └──┘  └─┘└───┘  └──┘ └──┘  └───┘└───┘ └───┘    └───┘
src   └──┘ └──┘  └─┘└───┘  └──┘ └──┘  └────────┘ └───┘    └───┘
typ   └──┘ └──┘  └─┘└───┘  └──┘ └──┘  └───┘└───┘ └───┘    └───┘
 93  λ p, by simp; induction p.unpair.2; simp [*, mul_succ]
id                          └──────┘             └──────┘
src          └──┘  └────────┘└──────┘└┘  └───────┘└──────┘└─
typ         └──┘  └────────┘└──────┘└┘  └───────┘└──────┘└─
doc          └──┘  └────────┘└──────┘└┘  └───────┘        └─
txt          └──┘  └────────┘        └┘  └───────┘        └─
par          └──┘  └────────┘        └┘  └───────┘        └─
pid                                 └┘      └──┘        
st          └───────────────────────────────────────────────
 94  
src  
typ  
doc  
txt  
par  
pid  
st   
 95  theorem pow : primrec (unpaired (^)) :=
id                 └─────┘  └──────┘ 
src                └─────┘  └──────┘ 
typ                └─────┘  └──────┘ 
doc                └─────┘
 96  (prec (const 1) (mul.comp (pair (right.comp right) left))).of_eq $
id    └──┘  └───┘     └─┘└───┘  └──┘  └───┘└───┘ └───┘  └──┘   └───┘
src   └──┘  └───┘     └─┘└───┘  └──┘  └────────┘ └───┘  └──┘   └───┘
typ   └──┘  └───┘     └─┘└───┘  └──┘  └───┘└───┘ └───┘  └──┘   └───┘
 97  λ p, by simp; induction p.unpair.2; simp [*, pow_succ]
id                          └──────┘             └──────┘
src          └──┘  └────────┘└──────┘└┘  └───────┘└──────┘└─
typ         └──┘  └────────┘└──────┘└┘  └───────┘└──────┘└─
doc          └──┘  └────────┘└──────┘└┘  └───────┘        └─
txt          └──┘  └────────┘        └┘  └───────┘        └─
par          └──┘  └────────┘        └┘  └───────┘        └─
pid                                 └┘      └──┘        
st          └───────────────────────────────────────────────
 98  
src  
typ  
doc  
txt  
par  
pid  
st   
 99  end primrec
100  
101  end nat
102  
103  section prio
104  set_option default_priority 100 -- see Note [default priority]
doc             └──────────────┘
105  /-- A `primcodable` type is an `encodable` type for which
106    the encode/decode functions are primitive recursive. -/
107  class primcodable (α : Type*) extends encodable α :=
id                          └───┘          └───────┘ 
src                                        └───────┘
typ                         └───┘          └───────┘ 
doc                                        └───────┘
108  (prim : nat.primrec (λ n, encodable.encode (decode n)))
id           └─────────┘      └──────────────┘  └────┘ 
src          └─────────┘       └──────────────┘
typ          └─────────┘      └──────────────┘  └────┘ 
doc          └─────────┘
109  end prio
110  
111  namespace primcodable
112  open nat.primrec
113  
114  @[priority 10] instance of_denumerable (α) [denumerable α] : primcodable α :=
id                                               └─────────┘     └─────────┘ 
src                                              └─────────┘      └─────────┘
typ                                              └─────────┘     └─────────┘ 
doc                                              └─────────┘      └─────────┘
115  ⟨succ.of_eq $ by simp⟩
id    └──┘└────┘
src   └──┘└────┘      └──┘
typ   └──┘└────┘      └──┘
doc                   └──┘
txt                   └──┘
par                   └──┘
st                   └───┘
116  
117  def of_equiv (α) {β} [primcodable α] (e : β ≃ α) : primcodable β :=
id                         └─────────┘              └─────────┘ 
src                        └─────────┘                 └─────────┘
typ                        └─────────┘              └─────────┘ 
doc                        └─────────┘                 └─────────┘
118  { prim := (primcodable.prim α).of_eq $ λ n,
id              └──────────────┘  └───┘      
src             └──────────────┘   └───┘
typ             └──────────────┘  └───┘      
119      show encode (decode α n) =
id            └────┘  └────┘    
src           └────┘  └────┘      
typ           └────┘  └────┘    
120        (option.cases_on (option.map e.symm (decode α n))
id          └─────────────┘  └────────┘ └───┘  └────┘  
src         └─────────────┘  └────────┘  └───┘  └────┘
typ         └─────────────┘  └────────┘ └───┘  └────┘  
121          0 (λ a, nat.succ (encode (e a))) : ℕ),
id                  └──────┘  └────┘         
src                  └──────┘  └────┘           
typ                 └──────┘  └────┘         
122      by cases decode α n; dsimp; simp,
id                └────┘  
src         └────┘└────┘    └───┘  └──┘
typ         └────┘└────┘  └───┘  └──┘
doc         └────┘          └───┘  └──┘
txt         └────┘          └───┘  └──┘
par         └────┘          └───┘  └──┘
pid                     
st         └────────────────────────────┘
123    ..encodable.of_equiv α e }
id       └────────────────┘  
src      └────────────────┘
typ      └────────────────┘  
doc      └────────────────┘
124  
125  instance empty : primcodable empty :=
id                    └─────────┘ └───┘
src                   └─────────┘ └───┘
typ                   └─────────┘ └───┘
doc                   └─────────┘
126  ⟨zero⟩
id    └──┘
src   └──┘
typ   └──┘
127  
128  instance unit : primcodable punit :=
id                   └─────────┘ └───┘
src                  └─────────┘ └───┘
typ                  └─────────┘ └───┘
doc                  └─────────┘
129  ⟨(cases1 1 zero).of_eq $ λ n, by cases n; simp⟩
id     └────┘   └──┘ └───┘                 
src    └────┘   └──┘ └───┘            └────┘   └──┘
typ    └────┘   └──┘ └───┘           └────┘  └──┘
doc                                   └────┘   └──┘
txt                                   └────┘   └──┘
par                                   └────┘   └──┘
pid                                        
st                                   └────────────┘
130  
131  instance option {α : Type*} [h : primcodable α] : primcodable (option α) :=
id                                    └─────────┘     └─────────┘  └────┘ 
src                                   └─────────┘      └─────────┘  └────┘
typ                                   └─────────┘     └─────────┘  └────┘ 
doc                                   └─────────┘      └─────────┘
132  ⟨(cases1 1 ((cases1 0 (succ.comp succ)).comp (primcodable.prim α))).of_eq $
id     └────┘     └────┘    └──┘└───┘ └──┘  └──┘   └──────────────┘    └───┘
src    └────┘     └────┘    └───────┘ └──┘  └──┘   └──────────────┘     └───┘
typ    └────┘     └────┘    └──┘└───┘ └──┘  └──┘   └──────────────┘    └───┘
133    λ n, by cases n; simp; cases decode α n; refl⟩
id                                └────┘  
src            └────┘   └──┘  └────┘└────┘    └──┘
typ           └────┘  └──┘  └────┘└────┘  └──┘
doc            └────┘   └──┘  └────┘          └──┘
txt            └────┘   └──┘  └────┘          └──┘
par            └────┘   └──┘  └────┘          └──┘
pid                                      
st            └────────────────────────────────────┘
134  
135  instance bool : primcodable bool :=
id                   └─────────┘ └──┘
src                  └─────────┘ └──┘
typ                  └─────────┘ └──┘
doc                  └─────────┘
136  ⟨(cases1 1 (cases1 2 zero)).of_eq $
id     └────┘    └────┘   └──┘  └───┘
src    └────┘    └────┘   └──┘  └───┘
typ    └────┘    └────┘   └──┘  └───┘
137  λ n, begin
id     
typ    
st        └─────
138    cases n, {refl}, cases n, {refl},
id                           
src    └────┘    └──┘   └────┘    └──┘
typ    └────┘   └──┘   └────┘   └──┘
doc    └────┘    └──┘   └────┘    └──┘
txt    └────┘    └──┘   └────┘    └──┘
par    └────┘    └──┘   └────┘    └──┘
pid                         
st   ────────┘└─────┘└┘└──────┘└─────┘└┘
139    rw decode_ge_two, {refl},
id        └───────────┘
src    └─┘└───────────┘   └──┘
typ    └─┘└───────────┘   └──┘
doc    └─┘                └──┘
txt    └─┘                └──┘
par    └─┘                └──┘
pid      
st   ─────────────────┘└─────┘└┘
140    exact dec_trivial
id           └─────────┘
src    └────┘└─────────┘
typ    └────┘└─────────┘
doc    └────┘└─────────┘
txt    └────┘           
par    └────┘           
pid                    
st   ───────────────────┘
141  end⟩
st   └─┘
142  
143  end primcodable
144  
145  /-- `primrec f` means `f` is primitive recursive (after
146    encoding its input and output as natural numbers). -/
147  def primrec {α β} [primcodable α] [primcodable β] (f : α → β) : Prop :=
id                      └─────────┘    └─────────┘           
src                     └─────────┘     └─────────┘
typ                     └─────────┘    └─────────┘           
doc                     └─────────┘     └─────────┘
148  nat.primrec (λ n, encode ((decode α n).map f))
id   └─────────┘      └────┘   └────┘   └─┘  
src  └─────────┘       └────┘   └────┘     └─┘
typ  └─────────┘      └────┘   └────┘   └─┘  
doc  └─────────┘
149  
150  namespace primrec
151  variables {α : Type*} {β : Type*} {σ : Type*}
id             
typ            
152  variables [primcodable α] [primcodable β] [primcodable σ]
id              └─────────┘     └─────────┘     └─────────┘
src             └─────────┘     └─────────┘     └─────────┘
typ             └─────────┘     └─────────┘     └─────────┘
doc             └─────────┘     └─────────┘     └─────────┘
153  open nat.primrec
154  
155  protected theorem encode : primrec (@encode α _) :=
id                              └─────┘   └────┘ 
src                             └─────┘   └────┘
typ                             └─────┘   └────┘ 
doc                             └─────┘
156  (primcodable.prim α).of_eq $ λ n, by cases decode α n; refl
id    └──────────────┘  └───┘                 └────┘  
src   └──────────────┘   └───┘            └────┘└────┘    └────
typ   └──────────────┘  └───┘           └────┘└────┘  └────
doc                                       └────┘          └────
txt                                       └────┘          └────
par                                       └────┘          └────
pid                                                          
st                                       └───────────────────────
157  
src  
typ  
doc  
txt  
par  
pid  
st   
158  protected theorem decode : primrec (decode α) :=
id                              └─────┘  └────┘ 
src                             └─────┘  └────┘
typ                             └─────┘  └────┘ 
doc                             └─────┘
159  succ.comp (primcodable.prim α)
id   └──┘└───┘  └──────────────┘ 
src  └───────┘  └──────────────┘
typ  └──┘└───┘  └──────────────┘ 
160  
161  theorem dom_denumerable {α β} [denumerable α] [primcodable β]
id                                  └─────────┘    └─────────┘ 
src                                 └─────────┘     └─────────┘
typ                                 └─────────┘    └─────────┘ 
doc                                 └─────────┘     └─────────┘
162    {f : α → β} : primrec f ↔ nat.primrec (λ n, encode (f (of_nat α n))) :=
id                 └─────┘   └─────────┘      └────┘    └────┘  
src                  └─────┘    └─────────┘       └────┘     └────┘
typ                └─────┘   └─────────┘      └────┘    └────┘  
doc                  └─────┘     └─────────┘
163  ⟨λ h, (pred.comp h).of_eq $ λ n, by simp; refl,
id         └──┘└───┘  └───┘      
src         └──┘└───┘   └───┘            └──┘  └──┘
typ        └──┘└───┘  └───┘           └──┘  └──┘
doc                                      └──┘  └──┘
txt                                      └──┘  └──┘
par                                      └──┘  └──┘
st                                      └─────────┘
164   λ h, (succ.comp h).of_eq $ λ n, by simp; refl⟩
id         └──┘└───┘  └───┘      
src         └───────┘   └───┘            └──┘  └──┘
typ        └──┘└───┘  └───┘           └──┘  └──┘
doc                                      └──┘  └──┘
txt                                      └──┘  └──┘
par                                      └──┘  └──┘
st                                      └─────────┘
165  
166  theorem nat_iff {f : ℕ → ℕ} : primrec f ↔ nat.primrec f :=
id                               └─────┘   └─────────┘ 
src                              └─────┘    └─────────┘
typ                              └─────┘   └─────────┘ 
doc                                └─────┘     └─────────┘
167  dom_denumerable
id   └─────────────┘
src  └─────────────┘
typ  └─────────────┘
168  
169  theorem encdec : primrec (λ n, encode (decode α n)) :=
id                    └─────┘      └────┘  └────┘  
src                   └─────┘       └────┘  └────┘
typ                   └─────┘      └────┘  └────┘  
doc                   └─────┘
170  nat_iff.2 (primcodable.prim α)
id   └─────┘   └──────────────┘ 
src  └─────┘   └──────────────┘
typ  └─────┘   └──────────────┘ 
171  
172  theorem option_some : primrec (@some α) :=
id                         └─────┘   └──┘ 
src                        └─────┘   └──┘
typ                        └─────┘   └──┘ 
doc                        └─────┘
173  ((cases1 0 (succ.comp succ)).comp (primcodable.prim α)).of_eq $
id     └────┘    └──┘└───┘ └──┘  └──┘   └──────────────┘   └───┘
src    └────┘    └───────┘ └──┘  └──┘   └──────────────┘    └───┘
typ    └────┘    └──┘└───┘ └──┘  └──┘   └──────────────┘   └───┘
174  λ n, by cases decode α n; simp
id                └────┘  
src          └────┘└────┘    └────
typ         └────┘└────┘  └────
doc          └────┘          └────
txt          └────┘          └────
par          └────┘          └────
pid                             
st          └───────────────────────
175  
src  
typ  
doc  
txt  
par  
pid  
st   
176  theorem of_eq {f g : α → σ} (hf : primrec f) (H : ∀ n, f n = g n) : primrec g :=
id                                   └─────┘                    └─────┘ 
src                                    └─────┘                          └─────┘
typ                                  └─────┘                    └─────┘ 
doc                                    └─────┘                           └─────┘
177  (funext H : f = g) ▸ hf
id    └────┘         └┘
src   └────┘           
typ   └────┘         └┘
178  
179  theorem const (x : σ) : primrec (λ a : α, x) :=
id                          └─────┘          
src                          └─────┘
typ                         └─────┘          
doc                          └─────┘
180  ((cases1 0 (const (encode x).succ)).comp (primcodable.prim α)).of_eq $
id     └────┘    └───┘  └────┘  └──┘   └──┘   └──────────────┘   └───┘
src    └────┘    └───┘  └────┘   └──┘   └──┘   └──────────────┘    └───┘
typ    └────┘    └───┘  └────┘  └──┘   └──┘   └──────────────┘   └───┘
181  λ n, by cases decode α n; refl
id                └────┘  
src          └────┘└────┘    └────
typ         └────┘└────┘  └────
doc          └────┘          └────
txt          └────┘          └────
par          └────┘          └────
pid                             
st          └───────────────────────
182  
src  
typ  
doc  
txt  
par  
pid  
st   
183  protected theorem id : primrec (@id α) :=
id                          └─────┘   └┘ 
src                         └─────┘   └┘
typ                         └─────┘   └┘ 
doc                         └─────┘
184  (primcodable.prim α).of_eq $ by simp
id    └──────────────┘  └───┘
src   └──────────────┘   └───┘       └────
typ   └──────────────┘  └───┘       └────
doc                                  └────
txt                                  └────
par                                  └────
pid                                      
st                                  └─────
185  
src  
typ  
doc  
txt  
par  
pid  
st   
186  theorem comp {f : β → σ} {g : α → β}
id                                  
typ                                 
187    (hf : primrec f) (hg : primrec g) : primrec (λ a, f (g a)) :=
id           └─────┘         └─────┘     └─────┘         
src          └─────┘          └─────┘      └─────┘
typ          └─────┘         └─────┘     └─────┘         
doc          └─────┘          └─────┘      └─────┘
188  ((cases1 0 (hf.comp $ pred.comp hg)).comp (primcodable.prim α)).of_eq $
id     └────┘    └┘└───┘   └──┘└───┘ └┘  └──┘   └──────────────┘   └───┘
src    └────┘      └───┘   └──┘└───┘     └──┘   └──────────────┘    └───┘
typ    └────┘    └┘└───┘   └──┘└───┘ └┘  └──┘   └──────────────┘   └───┘
189  λ n, begin
id     
typ    
st        └─────
190    cases decode α n, {refl},
id           └────┘  
src    └────┘└────┘     └──┘
typ    └────┘└────┘   └──┘
doc    └────┘           └──┘
txt    └────┘           └──┘
par    └────┘           └──┘
pid                
st   ─────────────────┘└─────┘└┘
191    simp [encodek]
id           └─────┘
src    └────┘└─────┘└┘
typ    └────┘└─────┘└┘
doc    └────┘       └┘
txt    └────┘       └┘
par    └────┘       └┘
pid               
st   ────────────────┘
192  end
st   └─┘
193  
194  theorem succ : primrec nat.succ := nat_iff.2 nat.primrec.succ
id                  └─────┘ └──────┘    └─────┘  └──────────────┘
src                 └─────┘ └──────┘    └─────┘  └──────────────┘
typ                 └─────┘ └──────┘    └─────┘  └──────────────┘
doc                 └─────┘
195  
196  theorem pred : primrec nat.pred := nat_iff.2 nat.primrec.pred
id                  └─────┘ └──────┘    └─────┘  └──────────────┘
src                 └─────┘ └──────┘    └─────┘  └──────────────┘
typ                 └─────┘ └──────┘    └─────┘  └──────────────┘
doc                 └─────┘
197  
198  theorem encode_iff {f : α → σ} : primrec (λ a, encode (f a)) ↔ primrec f :=
id                                  └─────┘      └────┘       └─────┘ 
src                                   └─────┘       └────┘         └─────┘
typ                                 └─────┘      └────┘       └─────┘ 
doc                                   └─────┘                       └─────┘
199  ⟨λ h, nat.primrec.of_eq h $ λ n, by cases decode α n; refl,
id        └───────────────┘                 └────┘  
src        └───────────────┘             └────┘└────┘    └──┘
typ       └───────────────┘           └────┘└────┘  └──┘
doc                                      └────┘          └──┘
txt                                      └────┘          └──┘
par                                      └────┘          └──┘
pid                                                  
st                                      └─────────────────────┘
200   primrec.encode.comp⟩
id    └────────────┘└───┘
src   └────────────┘└───┘
typ   └────────────┘└───┘
201  
202  theorem of_nat_iff {α β} [denumerable α] [primcodable β]
id                             └─────────┘    └─────────┘ 
src                            └─────────┘     └─────────┘
typ                            └─────────┘    └─────────┘ 
doc                            └─────────┘     └─────────┘
203    {f : α → β} : primrec f ↔ primrec (λ n, f (of_nat α n)) :=
id                 └─────┘   └─────┘        └────┘  
src                  └─────┘    └─────┘          └────┘
typ                └─────┘   └─────┘        └────┘  
doc                  └─────┘     └─────┘
204  dom_denumerable.trans $ nat_iff.symm.trans encode_iff
id   └─────────────┘└────┘   └─────┘└───┘└────┘ └────────┘
src  └─────────────┘└────┘   └─────┘└───┘└────┘ └────────┘
typ  └─────────────┘└────┘   └─────┘└───┘└────┘ └────────┘
205  
206  protected theorem of_nat (α) [denumerable α] : primrec (of_nat α) :=
id                                 └─────────┘     └─────┘  └────┘ 
src                                └─────────┘      └─────┘  └────┘
typ                                └─────────┘     └─────┘  └────┘ 
doc                                └─────────┘      └─────┘
207  of_nat_iff.1 primrec.id
id   └────────┘  └────────┘
src  └────────┘  └────────┘
typ  └────────┘  └────────┘
208  
209  theorem option_some_iff {f : α → σ} : primrec (λ a, some (f a)) ↔ primrec f :=
id                                       └─────┘      └──┘       └─────┘ 
src                                        └─────┘       └──┘         └─────┘
typ                                      └─────┘      └──┘       └─────┘ 
doc                                        └─────┘                     └─────┘
210  ⟨λ h, encode_iff.1 $ pred.comp $ encode_iff.2 h, option_some.comp⟩
id        └────────┘    └──┘└───┘   └────────┘    └─────────┘└───┘
src        └────────┘    └──┘└───┘   └────────┘     └─────────┘└───┘
typ       └────────┘    └──┘└───┘   └────────┘    └─────────┘└───┘
211  
212  theorem of_equiv {β} {e : β ≃ α} :
id                               
src                              
typ                              
doc                              
213    by haveI := primcodable.of_equiv α e; exact
id                 └──────────────────┘  
src       └───────┘└──────────────────┘    └─────
typ       └───────┘└──────────────────┘  └─────
doc       └───────┘                        └─────
txt       └───────┘                        └─────
par       └───────┘                        └─────
pid            └─┘                             
st       └─────────────────────────────────────────
214    primrec e :=
id     └─────┘ 
src  ─┘└─────┘ 
typ  ─┘└─────┘
doc  ─┘└─────┘ 
txt  ─┘        
par  ─┘        
pid  ─┘        
st   ───────────┘
215  (primcodable.prim α).of_eq $ λ n,
id    └──────────────┘  └───┘      
src   └──────────────┘   └───┘
typ   └──────────────┘  └───┘      
216  show _ = encode (option.map e (option.map _ _)),
id           └────┘  └────────┘   └────────┘
src          └────┘  └────────┘    └────────┘
typ          └────┘  └────────┘   └────────┘
217  by cases decode α n; simp
id            └────┘  
src     └────┘└────┘    └────
typ     └────┘└────┘  └────
doc     └────┘          └────
txt     └────┘          └────
par     └────┘          └────
pid                        
st     └───────────────────────
218  
src  
typ  
doc  
txt  
par  
pid  
st   
219  theorem of_equiv_symm {β} {e : β ≃ α} :
id                                    
src                                   
typ                                   
doc                                   
220    by haveI := primcodable.of_equiv α e; exact
id                 └──────────────────┘  
src       └───────┘└──────────────────┘    └─────
typ       └───────┘└──────────────────┘  └─────
doc       └───────┘                        └─────
txt       └───────┘                        └─────
par       └───────┘                        └─────
pid            └─┘                             
st       └─────────────────────────────────────────
221    primrec e.symm :=
id     └─────┘ └────┘
src  ─┘└─────┘└────┘
typ  ─┘└─────┘└────┘
doc  ─┘└─────┘      
txt  ─┘             
par  ─┘             
pid  ─┘             
st   ────────────────┘
222  by letI := primcodable.of_equiv α e; exact
id              └──────────────────┘  
src     └──────┘└──────────────────┘    └────┘
typ     └──────┘└──────────────────┘  └────┘
doc     └──────┘                        └────┘
txt     └──────┘                        └────┘
par     └──────┘                        └────┘
pid         └─┘                             
st     └────────────────────────────────────────
223  encode_iff.1
id   └────────┘
src  └────────┘└──
typ  └────────┘└──
doc            └──
txt            └──
par            └──
pid            └──
st   ─────────────
224    (show primrec (λ a, encode (e (e.symm a))), by simp [primrec.encode])
id           └─────┘       └────┘     └────┘                └────────────┘
src  ─┘     └─────┘  └──┘└────┘   └────┘ └──────┘└────┘└────────────┘└─
typ  ─┘     └─────┘  └──┘└────┘   └────┘ └──────┘└────┘└────────────┘└─
doc  ─┘     └─────┘  └──┘                └──────┘└────┘              └─
txt  ─┘              └──┘                └──────┘└────┘              └─
par  ─┘              └──┘                └──────┘└────┘              └─
pid  ─┘              └──┘                └────────────┘              └┘
st   ───────────────────────────────────────────────┘└────────────────────┘└─
225  
src  
typ  
doc  
txt  
par  
pid  
st   
226  theorem of_equiv_iff {β} (e : β ≃ α)
id                                   
src                                  
typ                                  
doc                                  
227    {f : σ → β} :
id             
typ            
228    by haveI := primcodable.of_equiv α e; exact
id                 └──────────────────┘  
src       └───────┘└──────────────────┘    └─────
typ       └───────┘└──────────────────┘  └─────
doc       └───────┘                        └─────
txt       └───────┘                        └─────
par       └───────┘                        └─────
pid            └─┘                             
st       └─────────────────────────────────────────
229    primrec (λ a, e (f a)) ↔ primrec f :=
id                            └─────┘ 
src  ─┘         └──┘    └─┘└─────┘ 
typ  ─┘         └──┘   └─┘└─────┘
doc  ─┘         └──┘    └─┘ └─────┘ 
txt  ─┘         └──┘    └─┘         
par  ─┘         └──┘    └─┘         
pid  ─┘         └──┘    └─┘         
st   ────────────────────────────────────┘
230  by letI := primcodable.of_equiv α e; exact
id              └──────────────────┘  
src     └──────┘└──────────────────┘    └────┘
typ     └──────┘└──────────────────┘  └────┘
doc     └──────┘                        └────┘
txt     └──────┘                        └────┘
par     └──────┘                        └────┘
pid         └─┘                             
st     └────────────────────────────────────────
231  ⟨λ h, (of_equiv_symm.comp h).of_eq (λ a, by simp), of_equiv.comp⟩
id          └────────────────┘                          └───────────┘
src    └──┘ └────────────────┘ └──────┘  └──┘  └──┘└─┘└───────────┘└─
typ    └──┘ └────────────────┘ └──────┘  └──┘  └──┘└─┘└───────────┘└─
doc    └──┘                    └──────┘  └──┘  └──┘└─┘             └─
txt    └──┘                    └──────┘  └──┘  └──┘└─┘             └─
par    └──┘                    └──────┘  └──┘  └──┘└─┘             └─
pid    └──┘                    └──────┘  └──┘  └──────┘             
st   ──────────────────────────────────────────┘└───┘└─────────────────
232  
src  
typ  
doc  
txt  
par  
pid  
st   
233  theorem of_equiv_symm_iff {β} (e : β ≃ α)
id                                        
src                                       
typ                                       
doc                                       
234    {f : σ → α} :
id             
typ            
235    by haveI := primcodable.of_equiv α e; exact
id                 └──────────────────┘  
src       └───────┘└──────────────────┘    └─────
typ       └───────┘└──────────────────┘  └─────
doc       └───────┘                        └─────
txt       └───────┘                        └─────
par       └───────┘                        └─────
pid            └─┘                             
st       └─────────────────────────────────────────
236    primrec (λ a, e.symm (f a)) ↔ primrec f :=
id                   └────┘         └─────┘ 
src  ─┘         └──┘└────┘   └─┘└─────┘ 
typ  ─┘         └──┘└────┘   └─┘└─────┘
doc  ─┘         └──┘         └─┘ └─────┘ 
txt  ─┘         └──┘         └─┘         
par  ─┘         └──┘         └─┘         
pid  ─┘         └──┘         └─┘         
st   ─────────────────────────────────────────┘
237  by letI := primcodable.of_equiv α e; exact
id              └──────────────────┘  
src     └──────┘└──────────────────┘    └────┘
typ     └──────┘└──────────────────┘  └────┘
doc     └──────┘                        └────┘
txt     └──────┘                        └────┘
par     └──────┘                        └────┘
pid         └─┘                             
st     └────────────────────────────────────────
238  ⟨λ h, (of_equiv.comp h).of_eq (λ a, by simp), of_equiv_symm.comp⟩
id          └───────────┘                          └────────────────┘
src    └──┘ └───────────┘ └──────┘  └──┘  └──┘└─┘└────────────────┘└─
typ    └──┘ └───────────┘ └──────┘  └──┘  └──┘└─┘└────────────────┘└─
doc    └──┘               └──────┘  └──┘  └──┘└─┘                  └─
txt    └──┘               └──────┘  └──┘  └──┘└─┘                  └─
par    └──┘               └──────┘  └──┘  └──┘└─┘                  └─
pid    └──┘               └──────┘  └──┘  └──────┘                  
st   ─────────────────────────────────────┘└───┘└──────────────────────
239  
src  
typ  
doc  
txt  
par  
pid  
st   
240  end primrec
241  
242  namespace primcodable
243  open nat.primrec
244  
245  instance prod {α β} [primcodable α] [primcodable β] : primcodable (α × β) :=
id                        └─────────┘    └─────────┘     └─────────┘    
src                       └─────────┘     └─────────┘      └─────────┘    
typ                       └─────────┘    └─────────┘     └─────────┘    
doc                       └─────────┘     └─────────┘      └─────────┘
246  ⟨((cases zero ((cases zero succ).comp
id      └───┘ └──┘   └───┘ └──┘ └──┘ └──┘
src     └───┘ └──┘   └───┘ └──┘ └──┘ └──┘
typ     └───┘ └──┘   └───┘ └──┘ └──┘ └──┘
247    (pair right ((primcodable.prim β).comp left)))).comp
id      └──┘ └───┘   └──────────────┘  └──┘  └──┘    └──┘
src     └──┘ └───┘   └──────────────┘   └──┘  └──┘    └──┘
typ     └──┘ └───┘   └──────────────┘  └──┘  └──┘    └──┘
248    (pair right ((primcodable.prim α).comp left))).of_eq $
id      └──┘ └───┘   └──────────────┘  └──┘  └──┘   └───┘
src     └──┘ └───┘   └──────────────┘   └──┘  └──┘   └───┘
typ     └──┘ └───┘   └──────────────┘  └──┘  └──┘   └───┘
249  λ n, begin
id     
typ    
st        └─────
250    simp [nat.unpaired],
id           └──────────┘
src    └────┘└──────────┘
typ    └────┘└──────────┘
doc    └────┘            
txt    └────┘            
par    └────┘            
pid                    
st   ────────────────────┘└─
251    cases decode α n.unpair.1, { simp },
id           └────┘  └──────┘
src    └────┘└────┘ └──────┘└┘    └───┘
typ    └────┘└────┘└──────┘└┘    └───┘
doc    └────┘       └──────┘└┘    └───┘
txt    └────┘               └┘    └───┘
par    └────┘               └┘    └───┘
pid                        └┘        
st   ──────────────────────────┘└──┘└───┘└┘
252    cases decode β n.unpair.2; simp
id           └────┘  └──────┘
src    └────┘└────┘ └──────┘└┘  └───┘
typ    └────┘└────┘└──────┘└┘  └───┘
doc    └────┘       └──────┘└┘  └───┘
txt    └────┘               └┘  └───┘
par    └────┘               └┘  └───┘
pid                        └┘      
st   ─────────────────────────────────┘
253  end⟩
st   └─┘
254  
255  end primcodable
256  
257  namespace primrec
258  variables {α : Type*} {σ : Type*} [primcodable α] [primcodable σ]
id                                      └─────────┘     └─────────┘
src                                     └─────────┘     └─────────┘
typ                                     └─────────┘     └─────────┘
doc                                     └─────────┘     └─────────┘
259  open nat.primrec
260  
261  theorem fst {α β} [primcodable α] [primcodable β] :
id                      └─────────┘    └─────────┘ 
src                     └─────────┘     └─────────┘
typ                     └─────────┘    └─────────┘ 
doc                     └─────────┘     └─────────┘
262    primrec (@prod.fst α β) :=
id     └─────┘   └──────┘  
src    └─────┘   └──────┘
typ    └─────┘   └──────┘  
doc    └─────┘
263  ((cases zero ((cases zero (nat.primrec.succ.comp left)).comp
id     └───┘ └──┘   └───┘ └──┘  └──────────────┘└───┘ └──┘  └──┘
src    └───┘ └──┘   └───┘ └──┘  └───────────────────┘ └──┘  └──┘
typ    └───┘ └──┘   └───┘ └──┘  └──────────────┘└───┘ └──┘  └──┘
264    (pair right ((primcodable.prim β).comp left)))).comp
id      └──┘ └───┘   └──────────────┘  └──┘  └──┘    └──┘
src     └──┘ └───┘   └──────────────┘   └──┘  └──┘    └──┘
typ     └──┘ └───┘   └──────────────┘  └──┘  └──┘    └──┘
265    (pair right ((primcodable.prim α).comp left))).of_eq $
id      └──┘ └───┘   └──────────────┘  └──┘  └──┘   └───┘
src     └──┘ └───┘   └──────────────┘   └──┘  └──┘   └───┘
typ     └──┘ └───┘   └──────────────┘  └──┘  └──┘   └───┘
266  λ n, begin
id     
typ    
st        └─────
267    simp,
src    └──┘
typ    └──┘
doc    └──┘
txt    └──┘
par    └──┘
st   ─────┘└─
268    cases decode α n.unpair.1; simp,
id           └────┘  └──────┘
src    └────┘└────┘ └──────┘└┘  └──┘
typ    └────┘└────┘└──────┘└┘  └──┘
doc    └────┘       └──────┘└┘  └──┘
txt    └────┘               └┘  └──┘
par    └────┘               └┘  └──┘
pid                        └┘
st   ────────────────────────────────┘└─
269    cases decode β n.unpair.2; simp
id           └────┘  └──────┘
src    └────┘└────┘ └──────┘└┘  └───┘
typ    └────┘└────┘└──────┘└┘  └───┘
doc    └────┘       └──────┘└┘  └───┘
txt    └────┘               └┘  └───┘
par    └────┘               └┘  └───┘
pid                        └┘      
st   ─────────────────────────────────┘
270  end
st   └─┘
271  
272  theorem snd {α β} [primcodable α] [primcodable β] :
id                      └─────────┘    └─────────┘ 
src                     └─────────┘     └─────────┘
typ                     └─────────┘    └─────────┘ 
doc                     └─────────┘     └─────────┘
273    primrec (@prod.snd α β) :=
id     └─────┘   └──────┘  
src    └─────┘   └──────┘
typ    └─────┘   └──────┘  
doc    └─────┘
274  ((cases zero ((cases zero (nat.primrec.succ.comp right)).comp
id     └───┘ └──┘   └───┘ └──┘  └──────────────┘└───┘ └───┘  └──┘
src    └───┘ └──┘   └───┘ └──┘  └───────────────────┘ └───┘  └──┘
typ    └───┘ └──┘   └───┘ └──┘  └──────────────┘└───┘ └───┘  └──┘
275    (pair right ((primcodable.prim β).comp left)))).comp
id      └──┘ └───┘   └──────────────┘  └──┘  └──┘    └──┘
src     └──┘ └───┘   └──────────────┘   └──┘  └──┘    └──┘
typ     └──┘ └───┘   └──────────────┘  └──┘  └──┘    └──┘
276    (pair right ((primcodable.prim α).comp left))).of_eq $
id      └──┘ └───┘   └──────────────┘  └──┘  └──┘   └───┘
src     └──┘ └───┘   └──────────────┘   └──┘  └──┘   └───┘
typ     └──┘ └───┘   └──────────────┘  └──┘  └──┘   └───┘
277  λ n, begin
id     
typ    
st        └─────
278    simp,
src    └──┘
typ    └──┘
doc    └──┘
txt    └──┘
par    └──┘
st   ─────┘└─
279    cases decode α n.unpair.1; simp,
id           └────┘  └──────┘
src    └────┘└────┘ └──────┘└┘  └──┘
typ    └────┘└────┘└──────┘└┘  └──┘
doc    └────┘       └──────┘└┘  └──┘
txt    └────┘               └┘  └──┘
par    └────┘               └┘  └──┘
pid                        └┘
st   ────────────────────────────────┘└─
280    cases decode β n.unpair.2; simp
id           └────┘  └──────┘
src    └────┘└────┘ └──────┘└┘  └───┘
typ    └────┘└────┘└──────┘└┘  └───┘
doc    └────┘       └──────┘└┘  └───┘
txt    └────┘               └┘  └───┘
par    └────┘               └┘  └───┘
pid                        └┘      
st   ─────────────────────────────────┘
281  end
st   └─┘
282  
283  theorem pair {α β γ} [primcodable α] [primcodable β] [primcodable γ]
id                         └─────────┘    └─────────┘    └─────────┘ 
src                        └─────────┘     └─────────┘     └─────────┘
typ                        └─────────┘    └─────────┘    └─────────┘ 
doc                        └─────────┘     └─────────┘     └─────────┘
284    {f : α → β} {g : α → γ} (hf : primrec f) (hg : primrec g) :
id                               └─────┘         └─────┘ 
src                                  └─────┘          └─────┘
typ                              └─────┘         └─────┘ 
doc                                  └─────┘          └─────┘
285    primrec (λ a, (f a, g a)) :=
id     └─────┘          
src    └─────┘       
typ    └─────┘          
doc    └─────┘
286  ((cases1 0 (nat.primrec.succ.comp $
id     └────┘    └──────────────┘└───┘
src    └────┘    └───────────────────┘
typ    └────┘    └──────────────┘└───┘
287    pair (nat.primrec.pred.comp hf) (nat.primrec.pred.comp hg))).comp
id     └──┘  └──────────────┘└───┘ └┘   └──────────────┘└───┘ └┘   └──┘
src    └──┘  └──────────────┘└───┘      └──────────────┘└───┘      └──┘
typ    └──┘  └──────────────┘└───┘ └┘   └──────────────┘└───┘ └┘   └──┘
288    (primcodable.prim α)).of_eq $
id      └──────────────┘   └───┘
src     └──────────────┘    └───┘
typ     └──────────────┘   └───┘
289  λ n, by cases decode α n; simp [encodek]; refl
id                └────┘          └─────┘
src          └────┘└────┘    └────┘└─────┘  └────
typ         └────┘└────┘  └────┘└─────┘  └────
doc          └────┘          └────┘         └────
txt          └────┘          └────┘         └────
par          └────┘          └────┘         └────
pid                                          
st          └───────────────────────────────────────
290  
src  
typ  
doc  
txt  
par  
pid  
st   
291  theorem unpair : primrec nat.unpair :=
id                    └─────┘ └────────┘
src                   └─────┘ └────────┘
typ                   └─────┘ └────────┘
doc                   └─────┘ └────────┘
292  (pair (nat_iff.2 nat.primrec.left) (nat_iff.2 nat.primrec.right)).of_eq $
id    └──┘  └─────┘  └──────────────┘   └─────┘  └───────────────┘  └───┘
src   └──┘  └─────┘  └──────────────┘   └─────┘  └───────────────┘  └───┘
typ   └──┘  └─────┘  └──────────────┘   └─────┘  └───────────────┘  └───┘
293  λ n, by simp
id     
src          └────
typ         └────
doc          └────
txt          └────
par          └────
pid              
st          └─────
294  
src  
typ  
doc  
txt  
par  
pid  
st   
295  theorem list_nth₁ : ∀ (l : list α), primrec l.nth
id                             └──┘    └─────┘ └──┘
src                             └──┘     └─────┘  └──┘
typ                            └──┘    └─────┘ └──┘
doc                                      └─────┘
296  | []     := dom_denumerable.2 zero
id     └┘        └─────────────┘  └──┘
src    └┘        └─────────────┘  └──┘
typ    └┘        └─────────────┘  └──┘
297  | (a::l) := dom_denumerable.2 $
id      └┘     └─────────────┘
src      └┘      └─────────────┘
typ     └┘     └─────────────┘
298    (cases1 (encode a).succ $ dom_denumerable.1 $ list_nth₁ l).of_eq $
id      └────┘  └────┘   └──┘    └─────────────┘    └───────┘   └───┘
src     └────┘  └────┘   └──┘    └─────────────┘                └───┘
typ     └────┘  └────┘   └──┘    └─────────────┘    └───────┘   └───┘
299    λ n, by cases n; simp
id                  
src            └────┘   └────
typ           └────┘  └────
doc            └────┘   └────
txt            └────┘   └────
par            └────┘   └────
pid                        
st            └──────────────
300  
src  
typ  
doc  
txt  
par  
pid  
st   
301  end primrec
302  
303  /-- `primrec₂ f` means `f` is a binary primitive recursive function.
304    This is technically unnecessary since we can always curry all
305    the arguments together, but there are enough natural two-arg
306    functions that it is convenient to express this directly. -/
307  def primrec₂ {α β σ} [primcodable α] [primcodable β] [primcodable σ] (f : α → β → σ) :=
id                         └─────────┘    └─────────┘    └─────────┘              
src                        └─────────┘     └─────────┘     └─────────┘
typ                        └─────────┘    └─────────┘    └─────────┘              
doc                        └─────────┘     └─────────┘     └─────────┘
308  primrec (λ p : α × β, f p.1 p.2)
id   └─────┘               
src  └─────┘                    
typ  └─────┘               
doc  └─────┘
309  
310  /-- `primrec_pred p` means `p : α → Prop` is a (decidable)
311    primitive recursive predicate, which is to say that
312    `to_bool ∘ p : α → bool` is primitive recursive. -/
313  def primrec_pred {α} [primcodable α] (p : α → Prop)
id                         └─────────┘        
src                        └─────────┘
typ                        └─────────┘        
doc                        └─────────┘
314    [decidable_pred p] := primrec (λ a, to_bool (p a))
id      └────────────┘      └─────┘      └─────┘   
src     └────────────┘       └─────┘       └─────┘
typ     └────────────┘      └─────┘      └─────┘   
doc                          └─────┘
315  
316  /-- `primrec_rel p` means `p : α → β → Prop` is a (decidable)
317    primitive recursive relation, which is to say that
318    `to_bool ∘ p : α → β → bool` is primitive recursive. -/
319  def primrec_rel {α β} [primcodable α] [primcodable β]
id                          └─────────┘    └─────────┘ 
src                         └─────────┘     └─────────┘
typ                         └─────────┘    └─────────┘ 
doc                         └─────────┘     └─────────┘
320    (s : α → β → Prop) [∀ a b, decidable (s a b)] :=
id                            └───────┘    
src                               └───────┘
typ                           └───────┘    
321  primrec₂ (λ a b, to_bool (s a b))
id   └──────┘       └─────┘    
src  └──────┘         └─────┘
typ  └──────┘       └─────┘    
doc  └──────┘
322  
323  namespace primrec₂
324  variables {α : Type*} {β : Type*} {σ : Type*}
id             
typ            
325  variables [primcodable α] [primcodable β] [primcodable σ]
id              └─────────┘     └─────────┘     └─────────┘
src             └─────────┘     └─────────┘     └─────────┘
typ             └─────────┘     └─────────┘     └─────────┘
doc             └─────────┘     └─────────┘     └─────────┘
326  
327  theorem of_eq {f g : α → β → σ} (hg : primrec₂ f) (H : ∀ a b, f a b = g a b) : primrec₂ g :=
id                                      └──────┘                       └──────┘ 
src                                        └──────┘                                └──────┘
typ                                     └──────┘                       └──────┘ 
doc                                        └──────┘                                 └──────┘
328  (by funext a b; apply H : f = g) ▸ hg
id                                  └┘
src      └────────┘  └────┘         
typ      └────────┘  └────┘        └┘
doc      └────────┘  └────┘ 
txt      └────────┘  └────┘ 
par      └────────┘  └────┘ 
pid            └──┘        
st      └───────────────────┘
329  
330  theorem const (x : σ) : primrec₂ (λ (a : α) (b : β), x) := primrec.const _
id                          └──────┘                        └───────────┘
src                          └──────┘                           └───────────┘
typ                         └──────┘                        └───────────┘
doc                          └──────┘
331  
332  protected theorem pair : primrec₂ (@prod.mk α β) :=
id                            └──────┘   └─────┘  
src                           └──────┘   └─────┘
typ                           └──────┘   └─────┘  
doc                           └──────┘
333  primrec.pair primrec.fst primrec.snd
id   └──────────┘ └─────────┘ └─────────┘
src  └──────────┘ └─────────┘ └─────────┘
typ  └──────────┘ └─────────┘ └─────────┘
334  
335  theorem left : primrec₂ (λ (a : α) (b : β), a) := primrec.fst
id                  └──────┘                        └─────────┘
src                 └──────┘                           └─────────┘
typ                 └──────┘                        └─────────┘
doc                 └──────┘
336  
337  theorem right : primrec₂ (λ (a : α) (b : β), b) := primrec.snd
id                   └──────┘                        └─────────┘
src                  └──────┘                           └─────────┘
typ                  └──────┘                        └─────────┘
doc                  └──────┘
338  
339  theorem mkpair : primrec₂ nat.mkpair :=
id                    └──────┘ └────────┘
src                   └──────┘ └────────┘
typ                   └──────┘ └────────┘
doc                   └──────┘ └────────┘
340  by simp [primrec₂, primrec]; constructor
id            └──────┘  └─────┘
src     └────┘└──────┘└┘└─────┘  └───────────
typ     └────┘└──────┘└┘└─────┘  └───────────
doc     └────┘└──────┘└┘└─────┘  └───────────
txt     └────┘        └┘         └───────────
par     └────┘        └┘         └───────────
pid                 └┘                    
st     └──────────────────────────────────────
341  
src  
typ  
doc  
txt  
par  
pid  
st   
342  theorem unpaired {f : ℕ → ℕ → α} : primrec (nat.unpaired f) ↔ primrec₂ f :=
id                                   └─────┘  └──────────┘    └──────┘ 
src                                   └─────┘  └──────────┘     └──────┘
typ                                  └─────┘  └──────────┘    └──────┘ 
doc                                     └─────┘                    └──────┘
343  ⟨λ h, by simpa using h.comp mkpair,
id                       └────┘ └────┘
src           └──────────┘└────┘└────┘
typ          └──────────┘└────┘└────┘
doc           └──────────┘      
txt           └──────────┘      
par           └──────────┘      
pid                └────┘      
st           └────────────────────────┘
344   λ h, h.comp primrec.unpair⟩
id        └───┘ └────────────┘
src         └───┘ └────────────┘
typ       └───┘ └────────────┘
345  
346  theorem unpaired' {f : ℕ → ℕ → ℕ} : nat.primrec (nat.unpaired f) ↔ primrec₂ f :=
id                                    └─────────┘  └──────────┘    └──────┘ 
src                                   └─────────┘  └──────────┘     └──────┘
typ                                   └─────────┘  └──────────┘    └──────┘ 
doc                                      └─────────┘                    └──────┘
347  primrec.nat_iff.symm.trans unpaired
id   └─────────────┘└───┘└────┘ └──────┘
src  └─────────────┘└───┘└────┘ └──────┘
typ  └─────────────┘└───┘└────┘ └──────┘
348  
349  theorem encode_iff {f : α → β → σ} : primrec₂ (λ a b, encode (f a b)) ↔ primrec₂ f :=
id                                     └──────┘       └────┘        └──────┘ 
src                                       └──────┘         └────┘           └──────┘
typ                                    └──────┘       └────┘        └──────┘ 
doc                                       └──────┘                           └──────┘
350  primrec.encode_iff
id   └────────────────┘
src  └────────────────┘
typ  └────────────────┘
351  
352  theorem option_some_iff {f : α → β → σ} : primrec₂ (λ a b, some (f a b)) ↔ primrec₂ f :=
id                                          └──────┘       └──┘        └──────┘ 
src                                            └──────┘         └──┘           └──────┘
typ                                         └──────┘       └──┘        └──────┘ 
doc                                            └──────┘                         └──────┘
353  primrec.option_some_iff
id   └─────────────────────┘
src  └─────────────────────┘
typ  └─────────────────────┘
354  
355  theorem of_nat_iff {α β σ}
356    [denumerable α] [denumerable β] [primcodable σ]
id      └─────────┘    └─────────┘    └─────────┘ 
src     └─────────┘     └─────────┘     └─────────┘
typ     └─────────┘    └─────────┘    └─────────┘ 
doc     └─────────┘     └─────────┘     └─────────┘
357    {f : α → β → σ} : primrec₂ f ↔ primrec₂ (λ m n : ℕ,
id                    └──────┘   └──────┘          
src                      └──────┘    └──────┘          
typ                   └──────┘   └──────┘          
doc                      └──────┘     └──────┘
358      f (of_nat α m) (of_nat β n)) :=
id         └────┘     └────┘  
src         └────┘       └────┘
typ        └────┘     └────┘  
359  (primrec.of_nat_iff.trans $ by simp).trans unpaired
id    └────────────────┘└────┘           └───┘  └──────┘
src   └────────────────┘└────┘      └──┘ └───┘  └──────┘
typ   └────────────────┘└────┘      └──┘ └───┘  └──────┘
doc                                 └──┘
txt                                 └──┘
par                                 └──┘
st                                 └───┘
360  
361  theorem uncurry {f : α → β → σ} : primrec (function.uncurry f) ↔ primrec₂ f :=
id                                  └─────┘  └──────────────┘    └──────┘ 
src                                    └─────┘  └──────────────┘     └──────┘
typ                                 └─────┘  └──────────────┘    └──────┘ 
doc                                    └─────┘                        └──────┘
362  by rw [show function.uncurry f = λ (p : α × β), f p.1 p.2,
id               └──────────────┘                
src     └──┘    └──────────────┘  └────┘  └─┘  └─┘ └───
typ     └──┘    └──────────────┘  └────┘└─┘ └─┘ └───
doc     └──┘                       └────┘   └─┘  └─┘ └───
txt     └──┘                       └────┘   └─┘  └─┘ └───
par     └──┘                       └────┘   └─┘  └─┘ └───
pid       └┘                       └────┘   └─┘  └─┘ └───
st     └────────────────────────────────────────────────────────
363         from funext $ λ ⟨a, b⟩, rfl]; refl
id               └────┘             └─┘
src  ───────────┘└────┘  └┘ └┘ └─┘└─┘  └────
typ  ───────────┘└────┘  └┘ └┘ └─┘└─┘  └────
doc  ───────────┘        └┘ └┘ └─┘     └────
txt  ───────────┘        └┘ └┘ └─┘     └────
par  ───────────┘        └┘ └┘ └─┘     └────
pid  ───────────┘        └┘ └┘ └─┘         
st   ─────────────────────────────────┘└──────
364  
src  
typ  
doc  
txt  
par  
pid  
st   
365  theorem curry {f : α × β → σ} : primrec₂ (function.curry f) ↔ primrec f :=
id                               └──────┘  └────────────┘    └─────┘ 
src                                 └──────┘  └────────────┘     └─────┘
typ                              └──────┘  └────────────┘    └─────┘ 
doc                                  └──────┘                      └─────┘
366  by rw [← uncurry, function.uncurry_curry]
id            └─────┘  └────────────────────┘
src     └────┘└─────┘└┘└────────────────────┘└─
typ     └────┘└─────┘└┘└────────────────────┘└─
doc     └────┘       └┘                      └─
txt     └────┘       └┘                      └─
par     └────┘       └┘                      └─
pid       └──┘       └┘                      
st     └────────────┘└──────────────────────┘
367  
src  
typ  
doc  
txt  
par  
pid  
st   
368  end primrec₂
369  
370  section comp
371  variables {α : Type*} {β : Type*} {γ : Type*} {δ : Type*} {σ : Type*}
372  variables [primcodable α] [primcodable β] [primcodable γ] [primcodable δ] [primcodable σ]
id              └─────────┘     └─────────┘     └─────────┘     └─────────┘     └─────────┘
src             └─────────┘     └─────────┘     └─────────┘     └─────────┘     └─────────┘
typ             └─────────┘     └─────────┘     └─────────┘     └─────────┘     └─────────┘
doc             └─────────┘     └─────────┘     └─────────┘     └─────────┘     └─────────┘
373  
374  theorem primrec.comp₂ {f : γ → σ} {g : α → β → γ}
id                                              
typ                                             
375    (hf : primrec f) (hg : primrec₂ g) :
id           └─────┘         └──────┘ 
src          └─────┘          └──────┘
typ          └─────┘         └──────┘ 
doc          └─────┘          └──────┘
376    primrec₂ (λ a b, f (g a b)) := hf.comp hg
id     └──────┘                 └┘└───┘ └┘
src    └──────┘                         └───┘
typ    └──────┘                 └┘└───┘ └┘
doc    └──────┘
377  
378  theorem primrec₂.comp
379    {f : β → γ → σ} {g : α → β} {h : α → γ}
id                                    
typ                                   
380    (hf : primrec₂ f) (hg : primrec g) (hh : primrec h) :
id           └──────┘         └─────┘         └─────┘ 
src          └──────┘          └─────┘          └─────┘
typ          └──────┘         └─────┘         └─────┘ 
doc          └──────┘          └─────┘          └─────┘
381    primrec (λ a, f (g a) (h a)) := hf.comp (hg.pair hh)
id     └─────┘                   └┘└───┘  └┘└───┘ └┘
src    └─────┘                           └───┘    └───┘
typ    └─────┘                   └┘└───┘  └┘└───┘ └┘
doc    └─────┘
382  
383  theorem primrec₂.comp₂
384    {f : γ → δ → σ} {g : α → β → γ} {h : α → β → δ}
id                                          
typ                                         
385    (hf : primrec₂ f) (hg : primrec₂ g) (hh : primrec₂ h) :
id           └──────┘         └──────┘         └──────┘ 
src          └──────┘          └──────┘          └──────┘
typ          └──────┘         └──────┘         └──────┘ 
doc          └──────┘          └──────┘          └──────┘
386    primrec₂ (λ a b, f (g a b) (h a b)) := hf.comp hg hh
id     └──────┘                      └┘└───┘ └┘ └┘
src    └──────┘                                 └───┘
typ    └──────┘                      └┘└───┘ └┘ └┘
doc    └──────┘
387  
388  theorem primrec_pred.comp
389    {p : β → Prop} [decidable_pred p] {f : α → β} :
id                    └────────────┘           
src                    └────────────┘
typ                   └────────────┘           
390    primrec_pred p → primrec f →
id     └──────────┘    └─────┘ 
src    └──────────┘     └─────┘
typ    └──────────┘    └─────┘ 
doc    └──────────┘     └─────┘
391    primrec_pred (λ a, p (f a)) := primrec.comp
id     └──────────┘               └──────────┘
src    └──────────┘                   └──────────┘
typ    └──────────┘               └──────────┘
doc    └──────────┘
392  
393  theorem primrec_rel.comp
394    {R : β → γ → Prop} [∀ a b, decidable (R a b)] {f : α → β} {g : α → γ} :
id                            └───────┘                         
src                               └───────┘
typ                           └───────┘                         
395    primrec_rel R → primrec f → primrec g →
id     └─────────┘    └─────┘    └─────┘ 
src    └─────────┘     └─────┘     └─────┘
typ    └─────────┘    └─────┘    └─────┘ 
doc    └─────────┘     └─────┘     └─────┘
396    primrec_pred (λ a, R (f a) (g a)) := primrec₂.comp
id     └──────────┘                   └───────────┘
src    └──────────┘                         └───────────┘
typ    └──────────┘                   └───────────┘
doc    └──────────┘
397  
398  theorem primrec_rel.comp₂
399    {R : γ → δ → Prop} [∀ a b, decidable (R a b)] {f : α → β → γ} {g : α → β → δ} :
id                            └───────┘                               
src                               └───────┘
typ                           └───────┘                               
400    primrec_rel R → primrec₂ f → primrec₂ g →
id     └─────────┘    └──────┘    └──────┘ 
src    └─────────┘     └──────┘     └──────┘
typ    └─────────┘    └──────┘    └──────┘ 
doc    └─────────┘     └──────┘     └──────┘
401    primrec_rel (λ a b, R (f a b) (g a b)) := primrec_rel.comp
id     └─────────┘                      └──────────────┘
src    └─────────┘                               └──────────────┘
typ    └─────────┘                      └──────────────┘
doc    └─────────┘
402  
403  end comp
404  
405  theorem primrec_pred.of_eq {α} [primcodable α]
id                                   └─────────┘ 
src                                  └─────────┘
typ                                  └─────────┘ 
doc                                  └─────────┘
406    {p q : α → Prop} [decidable_pred p] [decidable_pred q]
id                      └────────────┘    └────────────┘ 
src                      └────────────┘     └────────────┘
typ                     └────────────┘    └────────────┘ 
407    (hp : primrec_pred p) (H : ∀ a, p a ↔ q a) : primrec_pred q :=
id           └──────────┘                    └──────────┘ 
src          └──────────┘                          └──────────┘
typ          └──────────┘                    └──────────┘ 
doc          └──────────┘                           └──────────┘
408  primrec.of_eq hp (λ a, to_bool_congr (H a))
id   └───────────┘ └┘      └───────────┘   
src  └───────────┘          └───────────┘
typ  └───────────┘ └┘      └───────────┘   
409  
410  theorem primrec_rel.of_eq {α β} [primcodable α] [primcodable β]
id                                    └─────────┘    └─────────┘ 
src                                   └─────────┘     └─────────┘
typ                                   └─────────┘    └─────────┘ 
doc                                   └─────────┘     └─────────┘
411    {r s : α → β → Prop} [∀ a b, decidable (r a b)] [∀ a b, decidable (s a b)]
id                              └───────┘             └───────┘    
src                                 └───────┘                  └───────┘
typ                             └───────┘             └───────┘    
412    (hr : primrec_rel r) (H : ∀ a b, r a b ↔ s a b) : primrec_rel s :=
id           └─────────┘                       └─────────┘ 
src          └─────────┘                                └─────────┘
typ          └─────────┘                       └─────────┘ 
doc          └─────────┘                                 └─────────┘
413  primrec₂.of_eq hr (λ a b, to_bool_congr (H a b))
id   └────────────┘ └┘       └───────────┘    
src  └────────────┘            └───────────┘
typ  └────────────┘ └┘       └───────────┘    
414  
415  namespace primrec₂
416  variables {α : Type*} {β : Type*} {σ : Type*}
417  variables [primcodable α] [primcodable β] [primcodable σ]
id              └─────────┘     └─────────┘     └─────────┘
src             └─────────┘     └─────────┘     └─────────┘
typ             └─────────┘     └─────────┘     └─────────┘
doc             └─────────┘     └─────────┘     └─────────┘
418  open nat.primrec
419  
420  theorem swap {f : α → β → σ} (h : primrec₂ f) : primrec₂ (function.swap f) :=
id                                  └──────┘     └──────┘  └───────────┘ 
src                                    └──────┘      └──────┘  └───────────┘
typ                                 └──────┘     └──────┘  └───────────┘ 
doc                                    └──────┘      └──────┘
421  h.comp₂ primrec₂.right primrec₂.left
id   └────┘ └────────────┘ └───────────┘
src   └────┘ └────────────┘ └───────────┘
typ  └────┘ └────────────┘ └───────────┘
422  
423  theorem nat_iff {f : α → β → σ} : primrec₂ f ↔
id                                  └──────┘  
src                                    └──────┘   
typ                                 └──────┘  
doc                                    └──────┘
424    nat.primrec (nat.unpaired $ λ m n : ℕ,
id     └─────────┘  └──────────┘           
src    └─────────┘  └──────────┘           
typ    └─────────┘  └──────────┘           
doc    └─────────┘
425      encode $ (decode α m).bind $ λ a, (decode β n).map (f a)) :=
id       └────┘    └────┘   └──┘         └────┘   └─┘    
src      └────┘    └────┘     └──┘          └────┘     └─┘
typ      └────┘    └────┘   └──┘         └────┘   └─┘    
426  have ∀ (a : option α) (b : option β),
id               └────┘        └────┘ 
src              └────┘         └────┘
typ              └────┘        └────┘ 
427    option.map (λ (p : α × β), f p.1 p.2)
id     └────────┘                 
src    └────────┘                      
typ    └────────┘                 
428      (option.bind a (λ (a : α), option.map (prod.mk a) b)) =
id        └─────────┘             └────────┘  └─────┘      
src       └─────────┘               └────────┘  └─────┘        
typ       └─────────┘             └────────┘  └─────┘      
429    option.bind a (λ a, option.map (f a) b),
id     └─────────┘       └────────┘     
src    └─────────┘         └────────┘
typ    └─────────┘       └────────┘     
430  by intros; cases a; [refl, {cases b; refl}],
id                                   
src     └────┘  └────┘   └──┘   └────┘   └──┘
typ     └────┘  └────┘  └──┘   └────┘  └──┘
doc     └────┘  └────┘    └──┘   └────┘   └──┘
txt     └────┘  └────┘    └──┘   └────┘   └──┘
par     └────┘  └────┘    └──┘   └────┘   └──┘
pid                                  
st     └───────────────────────┘└────────────┘└┘
431  by simp [primrec₂, primrec, this]
id            └──────┘  └─────┘  └──┘
src     └────┘└──────┘└┘└─────┘└┘    └─
typ     └────┘└──────┘└┘└─────┘└┘└──┘└─
doc     └────┘└──────┘└┘└─────┘└┘    └─
txt     └────┘        └┘       └┘    └─
par     └────┘        └┘       └┘    └─
pid                 └┘       └┘    
st     └───────────────────────────────
432  
src  
typ  
doc  
txt  
par  
pid  
st   
433  theorem nat_iff' {f : α → β → σ} : primrec₂ f ↔ primrec₂ (λ m n : ℕ,
id                                   └──────┘   └──────┘          
src                                     └──────┘    └──────┘          
typ                                  └──────┘   └──────┘          
doc                                     └──────┘     └──────┘
434    option.bind (decode α m) (λ a, option.map (f a) (decode β n))) :=
id     └─────────┘  └────┘         └────────┘      └────┘  
src    └─────────┘  └────┘            └────────┘        └────┘
typ    └─────────┘  └────┘         └────────┘      └────┘  
435  nat_iff.trans $ unpaired'.trans encode_iff
id   └─────┘└────┘   └───────┘└────┘ └────────┘
src  └─────┘└────┘   └───────┘└────┘ └────────┘
typ  └─────┘└────┘   └───────┘└────┘ └────────┘
436  
437  end primrec₂
438  
439  namespace primrec
440  variables {α : Type*} {β : Type*} {γ : Type*} {δ : Type*} {σ : Type*}
441  variables [primcodable α] [primcodable β] [primcodable γ] [primcodable δ] [primcodable σ]
id              └─────────┘     └─────────┘     └─────────┘     └─────────┘     └─────────┘
src             └─────────┘     └─────────┘     └─────────┘     └─────────┘     └─────────┘
typ             └─────────┘     └─────────┘     └─────────┘     └─────────┘     └─────────┘
doc             └─────────┘     └─────────┘     └─────────┘     └─────────┘     └─────────┘
442  
443  theorem to₂ {f : α × β → σ} (hf : primrec f) : primrec₂ (λ a b, f (a, b)) :=
id                                 └─────┘     └──────┘          
src                                   └─────┘      └──────┘           
typ                                └─────┘     └──────┘          
doc                                    └─────┘      └──────┘
444  hf.of_eq $ λ ⟨a, b⟩, rfl
id   └┘└────┘            └─┘
src    └────┘             └─┘
typ  └┘└────┘            └─┘
445  
446  theorem nat_elim {f : α → β} {g : α → ℕ × β → β}
id                                           
src                                         
typ                                          
447    (hf : primrec f) (hg : primrec₂ g) :
id           └─────┘         └──────┘ 
src          └─────┘          └──────┘
typ          └─────┘         └──────┘ 
doc          └─────┘          └──────┘
448    primrec₂ (λ a (n : ℕ), n.elim (f a) (λ n IH, g a (n, IH))) :=
id     └──────┘             └───┘         └┘      └┘
src    └──────┘               └───┘                    
typ    └──────┘             └───┘         └┘      └┘
doc    └──────┘
449  primrec₂.nat_iff.2 $ ((nat.primrec.cases nat.primrec.zero $
id   └──────────────┘      └───────────────┘ └──────────────┘
src  └──────────────┘      └───────────────┘ └──────────────┘
typ  └──────────────┘      └───────────────┘ └──────────────┘
450      (nat.primrec.prec hf $ nat.primrec.comp hg $ nat.primrec.left.pair $
id        └──────────────┘ └┘   └──────────────┘ └┘   └──────────────┘└───┘
src       └──────────────┘      └──────────────┘      └───────────────────┘
typ       └──────────────┘ └┘   └──────────────┘ └┘   └──────────────┘└───┘
451        (nat.primrec.left.comp nat.primrec.right).pair $
id          └──────────────┘└───┘ └───────────────┘ └──┘
src         └───────────────────┘ └───────────────┘ └──┘
typ         └──────────────┘└───┘ └───────────────┘ └──┘
452        nat.primrec.pred.comp $ nat.primrec.right.comp nat.primrec.right).comp $
id         └──────────────┘└───┘   └───────────────┘└───┘ └───────────────┘ └──┘
src        └──────────────┘└───┘   └────────────────────┘ └───────────────┘ └──┘
typ        └──────────────┘└───┘   └───────────────┘└───┘ └───────────────┘ └──┘
453      nat.primrec.right.pair $
id       └───────────────┘└───┘
src      └────────────────────┘
typ      └───────────────┘└───┘
454        nat.primrec.right.comp nat.primrec.left).comp $
id         └───────────────┘└───┘ └──────────────┘ └──┘
src        └────────────────────┘ └──────────────┘ └──┘
typ        └───────────────┘└───┘ └──────────────┘ └──┘
455    nat.primrec.id.pair $ (primcodable.prim α).comp nat.primrec.left).of_eq $
id     └────────────┘└───┘    └──────────────┘  └──┘  └──────────────┘ └───┘
src    └────────────┘└───┘    └──────────────┘   └──┘  └──────────────┘ └───┘
typ    └────────────┘└───┘    └──────────────┘  └──┘  └──────────────┘ └───┘
456  λ n, begin
id     
typ    
st        └─────
457    simp,
src    └──┘
typ    └──┘
doc    └──┘
txt    └──┘
par    └──┘
st   ─────┘└─
458    cases decode α n.unpair.1 with a, {refl},
id           └────┘  └──────┘
src    └────┘└────┘ └──────┘└───────┘   └──┘
typ    └────┘└────┘└──────┘└───────┘   └──┘
doc    └────┘       └──────┘└───────┘   └──┘
txt    └────┘               └───────┘   └──┘
par    └────┘               └───────┘   └──┘
pid                        └───────┘
st   ─────────────────────────────────┘└─────┘└┘
459    simp [encodek],
id           └─────┘
src    └────┘└─────┘
typ    └────┘└─────┘
doc    └────┘       
txt    └────┘       
par    └────┘       
pid               
st   ───────────────┘└─
460    induction n.unpair.2 with m; simp [encodek],
id               └──────┘                 └─────┘
src    └────────┘└──────┘└───────┘  └────┘└─────┘
typ    └────────┘└──────┘└───────┘  └────┘└─────┘
doc    └────────┘└──────┘└───────┘  └────┘       
txt    └────────┘        └───────┘  └────┘       
par    └────────┘        └───────┘  └────┘       
pid                     └─┘└────┘             
st   ────────────────────────────────────────────┘└─
461    simp [ih, encodek]
id           └┘  └─────┘
src    └────┘  └┘└─────┘└┘
typ    └────┘└┘└┘└─────┘└┘
doc    └────┘  └┘       └┘
txt    └────┘  └┘       └┘
par    └────┘  └┘       └┘
pid          └┘       
st   ────────────────────┘
462  end
st   └─┘
463  
464  theorem nat_elim' {f : α → ℕ} {g : α → β} {h : α → ℕ × β → β}
id                                                      
src                                                     
typ                                                     
465    (hf : primrec f) (hg : primrec g) (hh : primrec₂ h) :
id           └─────┘         └─────┘         └──────┘ 
src          └─────┘          └─────┘          └──────┘
typ          └─────┘         └─────┘         └──────┘ 
doc          └─────┘          └─────┘          └──────┘
466    primrec (λ a, (f a).elim (g a) (λ n IH, h a (n, IH))) :=
id     └─────┘         └──┘          └┘      └┘
src    └─────┘            └──┘                     
typ    └─────┘         └──┘          └┘      └┘
doc    └─────┘
467  (nat_elim hg hh).comp primrec.id hf
id    └──────┘ └┘ └┘ └──┘  └────────┘ └┘
src   └──────┘       └──┘  └────────┘
typ   └──────┘ └┘ └┘ └──┘  └────────┘ └┘
468  
469  theorem nat_elim₁ {f : ℕ → α → α} (a : α) (hf : primrec₂ f) :
id                                               └──────┘ 
src                                                 └──────┘
typ                                              └──────┘ 
doc                                                  └──────┘
470    primrec (nat.elim a f) :=
id     └─────┘  └──────┘  
src    └─────┘  └──────┘
typ    └─────┘  └──────┘  
doc    └─────┘
471  nat_elim' primrec.id (const a) $ comp₂ hf primrec₂.right
id   └───────┘ └────────┘  └───┘     └───┘ └┘ └────────────┘
src  └───────┘ └────────┘  └───┘      └───┘    └────────────┘
typ  └───────┘ └────────┘  └───┘     └───┘ └┘ └────────────┘
472  
473  theorem nat_cases' {f : α → β} {g : α → ℕ → β}
id                                           
src                                          
typ                                          
474    (hf : primrec f) (hg : primrec₂ g) :
id           └─────┘         └──────┘ 
src          └─────┘          └──────┘
typ          └─────┘         └──────┘ 
doc          └─────┘          └──────┘
475    primrec₂ (λ a, nat.cases (f a) (g a)) :=
id     └──────┘      └───────┘       
src    └──────┘       └───────┘
typ    └──────┘      └───────┘       
doc    └──────┘
476  nat_elim hf $ hg.comp₂ primrec₂.left $
id   └──────┘ └┘   └┘└────┘ └───────────┘
src  └──────┘        └────┘ └───────────┘
typ  └──────┘ └┘   └┘└────┘ └───────────┘
477    comp₂ fst primrec₂.right
id     └───┘ └─┘ └────────────┘
src    └───┘ └─┘ └────────────┘
typ    └───┘ └─┘ └────────────┘
478  
479  theorem nat_cases {f : α → ℕ} {g : α → β} {h : α → ℕ → β}
id                                                    
src                                                    
typ                                                   
480    (hf : primrec f) (hg : primrec g) (hh : primrec₂ h) :
id           └─────┘         └─────┘         └──────┘ 
src          └─────┘          └─────┘          └──────┘
typ          └─────┘         └─────┘         └──────┘ 
doc          └─────┘          └─────┘          └──────┘
481    primrec (λ a, (f a).cases (g a) (h a)) :=
id     └─────┘         └───┘        
src    └─────┘            └───┘
typ    └─────┘         └───┘        
doc    └─────┘
482  (nat_cases' hg hh).comp primrec.id hf
id    └────────┘ └┘ └┘ └──┘  └────────┘ └┘
src   └────────┘       └──┘  └────────┘
typ   └────────┘ └┘ └┘ └──┘  └────────┘ └┘
483  
484  theorem nat_cases₁ {f : ℕ → α} (a : α) (hf : primrec f) :
id                                             └─────┘ 
src                                              └─────┘
typ                                            └─────┘ 
doc                                               └─────┘
485    primrec (nat.cases a f) :=
id     └─────┘  └───────┘  
src    └─────┘  └───────┘
typ    └─────┘  └───────┘  
doc    └─────┘
486  nat_cases primrec.id (const a) (comp₂ hf primrec₂.right)
id   └───────┘ └────────┘  └───┘    └───┘ └┘ └────────────┘
src  └───────┘ └────────┘  └───┘     └───┘    └────────────┘
typ  └───────┘ └────────┘  └───┘    └───┘ └┘ └────────────┘
487  
488  theorem nat_iterate {f : α → ℕ} {g : α → β} {h : α → β → β}
id                                                      
src                               
typ                                                     
489    (hf : primrec f) (hg : primrec g) (hh : primrec₂ h) :
id           └─────┘         └─────┘         └──────┘ 
src          └─────┘          └─────┘          └──────┘
typ          └─────┘         └─────┘         └──────┘ 
doc          └─────┘          └─────┘          └──────┘
490    primrec (λ a, (h a)^[f a] (g a)) :=
id     └─────┘         └┘    
src    └─────┘            └┘   
typ    └─────┘         └┘    
doc    └─────┘
491  (nat_elim' hf hg (hh.comp₂ primrec₂.left $ snd.comp₂ primrec₂.right)).of_eq $
id    └───────┘ └┘ └┘  └┘└────┘ └───────────┘   └─┘└────┘ └────────────┘  └───┘
src   └───────┘          └────┘ └───────────┘   └─┘└────┘ └────────────┘  └───┘
typ   └───────┘ └┘ └┘  └┘└────┘ └───────────┘   └─┘└────┘ └────────────┘  └───┘
492  λ a, by induction f a; simp [*, -nat.iterate_succ, nat.iterate_succ']
id                                                   └───────────────┘
src          └────────┘    └──────────────────────────┘└───────────────┘└─
typ         └────────┘  └──────────────────────────┘└───────────────┘└─
doc          └────────┘    └──────────────────────────┘                 └─
txt          └────────┘    └──────────────────────────┘                 └─
par          └────────┘    └──────────────────────────┘                 └─
pid                           └─────────────────────┘                 
st          └──────────────────────────────────────────────────────────────
493  
src  
typ  
doc  
txt  
par  
pid  
st   
494  theorem option_cases {o : α → option β} {f : α → σ} {g : α → β → σ}
id                                └────┘                        
src                                └────┘
typ                               └────┘                        
495    (ho : primrec o) (hf : primrec f) (hg : primrec₂ g) :
id           └─────┘         └─────┘         └──────┘ 
src          └─────┘          └─────┘          └──────┘
typ          └─────┘         └─────┘         └──────┘ 
doc          └─────┘          └─────┘          └──────┘
496    @primrec _ σ _ _ (λ a, option.cases_on (o a) (f a) (g a)) :=
id      └─────┘             └─────────────┘           
src     └─────┘               └─────────────┘
typ     └─────┘             └─────────────┘           
doc     └─────┘
497  encode_iff.1 $
id   └────────┘
src  └────────┘
typ  └────────┘
498  (nat_cases (encode_iff.2 ho) (encode_iff.2 hf) $
id    └───────┘  └────────┘  └┘   └────────┘  └┘
src   └───────┘  └────────┘       └────────┘
typ   └───────┘  └────────┘  └┘   └────────┘  └┘
499    pred.comp₂ $ primrec₂.encode_iff.2 $
id     └──┘└────┘   └─────────────────┘
src    └──┘└────┘   └─────────────────┘
typ    └──┘└────┘   └─────────────────┘
500    (primrec₂.nat_iff'.1 hg).comp₂
id      └───────────────┘  └┘ └───┘
src     └───────────────┘     └───┘
typ     └───────────────┘  └┘ └───┘
501      ((@primrec.encode α _).comp fst).to₂
id          └────────────┘    └──┘  └─┘ └─┘
src         └────────────┘     └──┘  └─┘ └─┘
typ         └────────────┘    └──┘  └─┘ └─┘
502      primrec₂.right).of_eq $
id       └────────────┘ └───┘
src      └────────────┘ └───┘
typ      └────────────┘ └───┘
503  λ a, by cases o a with b; simp [encodek]; refl
id                                └─────┘
src          └────┘  └─────┘  └────┘└─────┘  └────
typ         └────┘└─────┘  └────┘└─────┘  └────
doc          └────┘  └─────┘  └────┘         └────
txt          └────┘  └─────┘  └────┘         └────
par          └────┘  └─────┘  └────┘         └────
pid                 └─────┘                   
st          └───────────────────────────────────────
504  
src  
typ  
doc  
txt  
par  
pid  
st   
505  theorem option_bind {f : α → option β} {g : α → β → option σ}
id                               └────┘              └────┘ 
src                               └────┘                 └────┘
typ                              └────┘              └────┘ 
506    (hf : primrec f) (hg : primrec₂ g) :
id           └─────┘         └──────┘ 
src          └─────┘          └──────┘
typ          └─────┘         └──────┘ 
doc          └─────┘          └──────┘
507    primrec (λ a, (f a).bind (g a)) :=
id     └─────┘         └──┘    
src    └─────┘            └──┘
typ    └─────┘         └──┘    
doc    └─────┘
508  (option_cases hf (const none) hg).of_eq $
id    └──────────┘ └┘  └───┘ └──┘  └┘ └───┘
src   └──────────┘     └───┘ └──┘     └───┘
typ   └──────────┘ └┘  └───┘ └──┘  └┘ └───┘
509  λ a, by cases f a; refl
id                 
src          └────┘    └────
typ         └────┘  └────
doc          └────┘    └────
txt          └────┘    └────
par          └────┘    └────
pid                       
st          └────────────────
510  
src  
typ  
doc  
txt  
par  
pid  
st   
511  theorem option_bind₁ {f : α → option σ} (hf : primrec f) :
id                                └────┘         └─────┘ 
src                                └────┘          └─────┘
typ                               └────┘         └─────┘ 
doc                                                └─────┘
512    primrec (λ o, option.bind o f) :=
id     └─────┘      └─────────┘  
src    └─────┘       └─────────┘
typ    └─────┘      └─────────┘  
doc    └─────┘
513  option_bind primrec.id (hf.comp snd).to₂
id   └─────────┘ └────────┘  └┘└───┘ └─┘ └─┘
src  └─────────┘ └────────┘    └───┘ └─┘ └─┘
typ  └─────────┘ └────────┘  └┘└───┘ └─┘ └─┘
514  
515  theorem option_map {f : α → option β} {g : α → β → σ}
id                              └────┘              
src                              └────┘
typ                             └────┘              
516    (hf : primrec f) (hg : primrec₂ g) : primrec (λ a, (f a).map (g a)) :=
id           └─────┘         └──────┘     └─────┘         └─┘    
src          └─────┘          └──────┘      └─────┘            └─┘
typ          └─────┘         └──────┘     └─────┘         └─┘    
doc          └─────┘          └──────┘      └─────┘
517  option_bind hf (option_some.comp₂ hg)
id   └─────────┘ └┘  └─────────┘└────┘ └┘
src  └─────────┘     └─────────┘└────┘
typ  └─────────┘ └┘  └─────────┘└────┘ └┘
518  
519  theorem option_map₁ {f : α → σ} (hf : primrec f) : primrec (option.map f) :=
id                                       └─────┘     └─────┘  └────────┘ 
src                                        └─────┘      └─────┘  └────────┘
typ                                      └─────┘     └─────┘  └────────┘ 
doc                                        └─────┘      └─────┘
520  option_map primrec.id (hf.comp snd).to₂
id   └────────┘ └────────┘  └┘└───┘ └─┘ └─┘
src  └────────┘ └────────┘    └───┘ └─┘ └─┘
typ  └────────┘ └────────┘  └┘└───┘ └─┘ └─┘
521  
522  theorem option_iget [inhabited α] : primrec (@option.iget α _) :=
id                        └───────┘     └─────┘   └─────────┘ 
src                       └───────┘      └─────┘   └─────────┘
typ                       └───────┘     └─────┘   └─────────┘ 
doc                                      └─────┘   └─────────┘
523  (option_cases primrec.id (const $ default α) primrec₂.right).of_eq $
id    └──────────┘ └────────┘  └───┘   └─────┘   └────────────┘ └───┘
src   └──────────┘ └────────┘  └───┘   └─────┘    └────────────┘ └───┘
typ   └──────────┘ └────────┘  └───┘   └─────┘   └────────────┘ └───┘
524  λ o, by cases o; refl
id                
src          └────┘   └────
typ         └────┘  └────
doc          └────┘   └────
txt          └────┘   └────
par          └────┘   └────
pid                      
st          └──────────────
525  
src  
typ  
doc  
txt  
par  
pid  
st   
526  theorem option_is_some : primrec (@option.is_some α) :=
id                            └─────┘   └────────────┘ 
src                           └─────┘   └────────────┘
typ                           └─────┘   └────────────┘ 
doc                           └─────┘
527  (option_cases primrec.id (const ff) (const tt).to₂).of_eq $
id    └──────────┘ └────────┘  └───┘ └┘   └───┘ └┘ └─┘  └───┘
src   └──────────┘ └────────┘  └───┘ └┘   └───┘ └┘ └─┘  └───┘
typ   └──────────┘ └────────┘  └───┘ └┘   └───┘ └┘ └─┘  └───┘
528  λ o, by cases o; refl
id                
src          └────┘   └────
typ         └────┘  └────
doc          └────┘   └────
txt          └────┘   └────
par          └────┘   └────
pid                      
st          └──────────────
529  
src  
typ  
doc  
txt  
par  
pid  
st   
530  theorem bind_decode_iff {f : α → β → option σ} : primrec₂ (λ a n,
id                                      └────┘     └──────┘     
src                                       └────┘      └──────┘
typ                                     └────┘     └──────┘     
doc                                                   └──────┘
531    (decode β n).bind (f a)) ↔ primrec₂ f :=
id      └────┘   └──┘        └──────┘ 
src     └────┘     └──┘          └──────┘
typ     └────┘   └──┘        └──────┘ 
doc                               └──────┘
532  ⟨λ h, by simpa [encodek] using
id                  └─────┘
src           └─────┘└─────┘└───────
typ          └─────┘└─────┘└───────
doc           └─────┘       └───────
txt           └─────┘       └───────
par           └─────┘       └───────
pid                       └─────
st           └──────────────────────
533     h.comp fst ((@primrec.encode β _).comp snd),
id      └────┘ └─┘    └────────────┘          └─┘
src  ──┘└────┘└─┘   └────────────┘ └───────┘└─┘
typ  ──┘└────┘└─┘   └────────────┘└───────┘└─┘
doc  ──┘                           └───────┘   
txt  ──┘                           └───────┘   
par  ──┘                           └───────┘   
pid  ──┘                           └───────┘   
st   ─────────────────────────────────────────────┘
534   λ h, option_bind (primrec.decode.comp snd) $
id        └─────────┘  └────────────┘└───┘ └─┘
src        └─────────┘  └────────────┘└───┘ └─┘
typ       └─────────┘  └────────────┘└───┘ └─┘
535     h.comp (fst.comp fst) snd⟩
id      └───┘  └─┘└───┘ └─┘  └─┘
src      └───┘  └─┘└───┘ └─┘  └─┘
typ     └───┘  └─┘└───┘ └─┘  └─┘
536  
537  theorem map_decode_iff {f : α → β → σ} : primrec₂ (λ a n,
id                                         └──────┘     
src                                           └──────┘
typ                                        └──────┘     
doc                                           └──────┘
538    (decode β n).map (f a)) ↔ primrec₂ f :=
id      └────┘   └─┘        └──────┘ 
src     └────┘     └─┘          └──────┘
typ     └────┘   └─┘        └──────┘ 
doc                              └──────┘
539  bind_decode_iff.trans primrec₂.option_some_iff
id   └─────────────┘└────┘ └──────────────────────┘
src  └─────────────┘└────┘ └──────────────────────┘
typ  └─────────────┘└────┘ └──────────────────────┘
540  
541  theorem nat_add : primrec₂ ((+) : ℕ → ℕ → ℕ) :=
id                     └──────┘             
src                    └──────┘             
typ                    └──────┘             
doc                    └──────┘
542  primrec₂.unpaired'.1 nat.primrec.add
id   └────────────────┘  └─────────────┘
src  └────────────────┘  └─────────────┘
typ  └────────────────┘  └─────────────┘
543  
544  theorem nat_sub : primrec₂ (has_sub.sub : ℕ → ℕ → ℕ) :=
id                     └──────┘  └─────────┘         
src                    └──────┘  └─────────┘         
typ                    └──────┘  └─────────┘         
doc                    └──────┘
545  primrec₂.unpaired'.1 nat.primrec.sub
id   └────────────────┘  └─────────────┘
src  └────────────────┘  └─────────────┘
typ  └────────────────┘  └─────────────┘
546  
547  theorem nat_mul : primrec₂ ((*) : ℕ → ℕ → ℕ) :=
id                     └──────┘             
src                    └──────┘             
typ                    └──────┘             
doc                    └──────┘
548  primrec₂.unpaired'.1 nat.primrec.mul
id   └────────────────┘  └─────────────┘
src  └────────────────┘  └─────────────┘
typ  └────────────────┘  └─────────────┘
549  
550  theorem cond {c : α → bool} {f : α → σ} {g : α → σ}
id                        └──┘                    
src                        └──┘
typ                       └──┘                    
551    (hc : primrec c) (hf : primrec f) (hg : primrec g) :
id           └─────┘         └─────┘         └─────┘ 
src          └─────┘          └─────┘          └─────┘
typ          └─────┘         └─────┘         └─────┘ 
doc          └─────┘          └─────┘          └─────┘
552    primrec (λ a, cond (c a) (f a) (g a)) :=
id     └─────┘      └──┘           
src    └─────┘       └──┘
typ    └─────┘      └──┘           
doc    └─────┘
553  (nat_cases (encode_iff.2 hc) hg (hf.comp fst).to₂).of_eq $
id    └───────┘  └────────┘  └┘  └┘  └┘└───┘ └─┘ └─┘  └───┘
src   └───────┘  └────────┘            └───┘ └─┘ └─┘  └───┘
typ   └───────┘  └────────┘  └┘  └┘  └┘└───┘ └─┘ └─┘  └───┘
554  λ a, by cases c a; refl
id                 
src          └────┘    └────
typ         └────┘  └────
doc          └────┘    └────
txt          └────┘    └────
par          └────┘    └────
pid                       
st          └────────────────
555  
src  
typ  
doc  
txt  
par  
pid  
st   
556  theorem ite {c : α → Prop} [decidable_pred c] {f : α → σ} {g : α → σ}
id                              └────────────┘                     
src                              └────────────┘
typ                             └────────────┘                     
557    (hc : primrec_pred c) (hf : primrec f) (hg : primrec g) :
id           └──────────┘         └─────┘         └─────┘ 
src          └──────────┘          └─────┘          └─────┘
typ          └──────────┘         └─────┘         └─────┘ 
doc          └──────────┘          └─────┘          └─────┘
558    primrec (λ a, if c a then f a else g a) :=
id     └─────┘                        
src    └─────┘
typ    └─────┘                        
doc    └─────┘
559  by simpa using cond hc hf hg
id                  └──┘ └┘ └┘ └┘
src     └──────────┘└──┘      
typ     └──────────┘└──┘└┘└┘└┘
doc     └──────────┘          
txt     └──────────┘          
par     └──────────┘          
pid          └────┘          
st     └──────────────────────────
560  
src  
typ  
doc  
txt  
par  
pid  
st   
561  theorem nat_le : primrec_rel ((≤) : ℕ → ℕ → Prop) :=
id                    └─────────┘          
src                   └─────────┘          
typ                   └─────────┘          
doc                   └─────────┘
562  (nat_cases nat_sub (const tt) (const ff).to₂).of_eq $
id    └───────┘ └─────┘  └───┘ └┘   └───┘ └┘ └─┘  └───┘
src   └───────┘ └─────┘  └───┘ └┘   └───┘ └┘ └─┘  └───┘
typ   └───────┘ └─────┘  └───┘ └┘   └───┘ └┘ └─┘  └───┘
563  λ p, begin
id     
typ    
st        └─────
564    dsimp [function.swap],
id            └───────────┘
src    └─────┘└───────────┘
typ    └─────┘└───────────┘
doc    └─────┘             
txt    └─────┘             
par    └─────┘             
pid                      
st   ──────────────────────┘└─
565    cases e : p.1 - p.2 with n,
id                    
src    └────┘ └─┘ └─┘ └───────┘
typ    └────┘ └─┘ └─┘└───────┘
doc    └────┘ └─┘ └─┘  └───────┘
txt    └────┘ └─┘ └─┘  └───────┘
par    └────┘ └─┘ └─┘  └───────┘
pid          └─┘ └─┘  └───────┘
st   ───────────────────────────┘└─
566    { simp [nat.sub_eq_zero_iff_le.1 e] },
id             └────────────────────┘   
src      └────┘└────────────────────┘└─┘ └┘
typ      └────┘└────────────────────┘└─┘└┘
doc      └────┘                      └─┘ └┘
txt      └────┘                      └─┘ └┘
par      └────┘                      └─┘ └┘
pid                                └─┘ 
st   ───┘└────────────────────────────────┘└┘
567    { simp [not_le.2 (nat.lt_of_sub_eq_succ e)] }
id             └────┘    └───────────────────┘ 
src      └────┘└────┘└─┘ └───────────────────┘ └─┘
typ      └────┘└────┘└─┘ └───────────────────┘└─┘
doc      └────┘      └─┘                       └─┘
txt      └────┘      └─┘                       └─┘
par      └────┘      └─┘                       └─┘
pid                └─┘                       └┘
st   ─────────────────────────────────────────────┘└─
568  end
st   ──┘
569  
570  theorem nat_min : primrec₂ (@min ℕ _) := ite nat_le fst snd
id                     └──────┘   └─┘        └─┘ └────┘ └─┘ └─┘
src                    └──────┘   └─┘        └─┘ └────┘ └─┘ └─┘
typ                    └──────┘   └─┘        └─┘ └────┘ └─┘ └─┘
doc                    └──────┘
571  theorem nat_max : primrec₂ (@max ℕ _) := ite nat_le snd fst
id                     └──────┘   └─┘        └─┘ └────┘ └─┘ └─┘
src                    └──────┘   └─┘        └─┘ └────┘ └─┘ └─┘
typ                    └──────┘   └─┘        └─┘ └────┘ └─┘ └─┘
doc                    └──────┘
572  
573  theorem dom_bool (f : bool → α) : primrec f :=
id                         └──┘       └─────┘ 
src                        └──┘        └─────┘
typ                        └──┘       └─────┘ 
doc                                    └─────┘
574  (cond primrec.id (const (f tt)) (const (f ff))).of_eq $
id    └──┘ └────────┘  └───┘   └┘    └───┘   └┘   └───┘
src   └──┘ └────────┘  └───┘    └┘    └───┘    └┘   └───┘
typ   └──┘ └────────┘  └───┘   └┘    └───┘   └┘   └───┘
575  λ b, by cases b; refl
id                
src          └────┘   └────
typ         └────┘  └────
doc          └────┘   └────
txt          └────┘   └────
par          └────┘   └────
pid                      
st          └──────────────
576  
src  
typ  
doc  
txt  
par  
pid  
st   
577  theorem dom_bool₂ (f : bool → bool → α) : primrec₂ f :=
id                          └──┘   └──┘       └──────┘ 
src                         └──┘   └──┘        └──────┘
typ                         └──┘   └──┘       └──────┘ 
doc                                            └──────┘
578  (cond fst
id    └──┘ └─┘
src   └──┘ └─┘
typ   └──┘ └─┘
579    ((dom_bool (f tt)).comp snd)
id       └──────┘   └┘  └──┘  └─┘
src      └──────┘    └┘  └──┘  └─┘
typ      └──────┘   └┘  └──┘  └─┘
580    ((dom_bool (f ff)).comp snd)).of_eq $
id       └──────┘   └┘  └──┘  └─┘  └───┘
src      └──────┘    └┘  └──┘  └─┘  └───┘
typ      └──────┘   └┘  └──┘  └─┘  └───┘
581  λ ⟨a, b⟩, by cases a; refl
id                     
src               └────┘   └────
typ              └────┘  └────
doc               └────┘   └────
txt               └────┘   └────
par               └────┘   └────
pid                           
st               └──────────────
582  
src  
typ  
doc  
txt  
par  
pid  
st   
583  protected theorem bnot : primrec bnot := dom_bool _
id                            └─────┘ └──┘    └──────┘
src                           └─────┘ └──┘    └──────┘
typ                           └─────┘ └──┘    └──────┘
doc                           └─────┘
584  protected theorem band : primrec₂ band := dom_bool₂ _
id                            └──────┘ └──┘    └───────┘
src                           └──────┘ └──┘    └───────┘
typ                           └──────┘ └──┘    └───────┘
doc                           └──────┘
585  protected theorem bor : primrec₂ bor := dom_bool₂ _
id                           └──────┘ └─┘    └───────┘
src                          └──────┘ └─┘    └───────┘
typ                          └──────┘ └─┘    └───────┘
doc                          └──────┘
586  
587  protected theorem not {p : α → Prop} [decidable_pred p]
id                                        └────────────┘ 
src                                        └────────────┘
typ                                       └────────────┘ 
588    (hp : primrec_pred p) : primrec_pred (λ a, ¬ p a) :=
id           └──────────┘     └──────────┘        
src          └──────────┘      └──────────┘       
typ          └──────────┘     └──────────┘        
doc          └──────────┘      └──────────┘
589  (primrec.bnot.comp hp).of_eq $ λ n, by simp
id    └──────────┘└───┘ └┘ └───┘      
src   └──────────┘└───┘    └───┘            └────
typ   └──────────┘└───┘ └┘ └───┘           └────
doc                                         └────
txt                                         └────
par                                         └────
pid                                             
st                                         └─────
590  
src  
typ  
doc  
txt  
par  
pid  
st   
591  protected theorem and {p q : α → Prop}
id                                
typ                               
592    [decidable_pred p] [decidable_pred q]
id      └────────────┘    └────────────┘ 
src     └────────────┘     └────────────┘
typ     └────────────┘    └────────────┘ 
593    (hp : primrec_pred p) (hq : primrec_pred q) :
id           └──────────┘         └──────────┘ 
src          └──────────┘          └──────────┘
typ          └──────────┘         └──────────┘ 
doc          └──────────┘          └──────────┘
594    primrec_pred (λ a, p a ∧ q a) :=
id     └──────────┘          
src    └──────────┘           
typ    └──────────┘          
doc    └──────────┘
595  (primrec.band.comp hp hq).of_eq $ λ n, by simp
id    └──────────┘└───┘ └┘ └┘ └───┘      
src   └──────────┘└───┘       └───┘            └────
typ   └──────────┘└───┘ └┘ └┘ └───┘           └────
doc                                            └────
txt                                            └────
par                                            └────
pid                                                
st                                            └─────
596  
src  
typ  
doc  
txt  
par  
pid  
st   
597  protected theorem or {p q : α → Prop}
id                               
typ                              
598    [decidable_pred p] [decidable_pred q]
id      └────────────┘    └────────────┘ 
src     └────────────┘     └────────────┘
typ     └────────────┘    └────────────┘ 
599    (hp : primrec_pred p) (hq : primrec_pred q) :
id           └──────────┘         └──────────┘ 
src          └──────────┘          └──────────┘
typ          └──────────┘         └──────────┘ 
doc          └──────────┘          └──────────┘
600    primrec_pred (λ a, p a ∨ q a) :=
id     └──────────┘          
src    └──────────┘           
typ    └──────────┘          
doc    └──────────┘
601  (primrec.bor.comp hp hq).of_eq $ λ n, by simp
id    └─────────┘└───┘ └┘ └┘ └───┘      
src   └─────────┘└───┘       └───┘            └────
typ   └─────────┘└───┘ └┘ └┘ └───┘           └────
doc                                           └────
txt                                           └────
par                                           └────
pid                                               
st                                           └─────
602  
src  
typ  
doc  
txt  
par  
pid  
st   
603  protected theorem eq [decidable_eq α] : primrec_rel (@eq α) :=
id                         └──────────┘     └─────────┘   └┘ 
src                        └──────────┘      └─────────┘   └┘
typ                        └──────────┘     └─────────┘   └┘ 
doc                                          └─────────┘
604  have primrec_rel (λ a b : ℕ, a = b), from
id        └─────────┘              
src       └─────────┘              
typ       └─────────┘              
doc       └─────────┘
605    (primrec.and nat_le nat_le.swap).of_eq $
id      └─────────┘ └────┘ └────┘└───┘ └───┘
src     └─────────┘ └────┘ └────┘└───┘ └───┘
typ     └─────────┘ └────┘ └────┘└───┘ └───┘
606    λ a, by simp [le_antisymm_iff],
id                  └─────────────┘
src            └────┘└─────────────┘
typ           └────┘└─────────────┘
doc            └────┘               
txt            └────┘               
par            └────┘               
pid                               
st            └─────────────────────┘
607  (this.comp₂
id    └──┘└────┘
src       └────┘
typ   └──┘└────┘
608    (primrec.encode.comp₂ primrec₂.left)
id      └────────────┘└────┘ └───────────┘
src     └────────────┘└────┘ └───────────┘
typ     └────────────┘└────┘ └───────────┘
609    (primrec.encode.comp₂ primrec₂.right)).of_eq $
id      └────────────┘└────┘ └────────────┘  └───┘
src     └────────────┘└────┘ └────────────┘  └───┘
typ     └────────────┘└────┘ └────────────┘  └───┘
610  λ a b, encode_injective.eq_iff
id        └──────────────┘└─────┘
src         └──────────────┘└─────┘
typ       └──────────────┘└─────┘
611  
612  theorem nat_lt : primrec_rel ((<) : ℕ → ℕ → Prop) :=
id                    └─────────┘          
src                   └─────────┘          
typ                   └─────────┘          
doc                   └─────────┘
613  (nat_le.comp snd fst).not.of_eq $ λ p, by simp
id    └────┘└───┘ └─┘ └─┘ └─┘ └───┘      
src   └────┘└───┘ └─┘ └─┘ └─┘ └───┘            └────
typ   └────┘└───┘ └─┘ └─┘ └─┘ └───┘           └────
doc                                            └────
txt                                            └────
par                                            └────
pid                                                
st                                            └─────
614  
src  
typ  
doc  
txt  
par  
pid  
st   
615  theorem option_guard {p : α → β → Prop}
id                                
typ                               
616    [∀ a b, decidable (p a b)] (hp : primrec_rel p)
id           └───────┘             └─────────┘ 
src            └───────┘                └─────────┘
typ          └───────┘             └─────────┘ 
doc                                     └─────────┘
617    {f : α → β} (hf : primrec f) :
id                     └─────┘ 
src                      └─────┘
typ                    └─────┘ 
doc                      └─────┘
618    primrec (λ a, option.guard (p a) (f a)) :=
id     └─────┘      └──────────┘       
src    └─────┘       └──────────┘
typ    └─────┘      └──────────┘       
doc    └─────┘       └──────────┘
619  ite (hp.comp primrec.id hf) (option_some_iff.2 hf) (const none)
id   └─┘  └┘└───┘ └────────┘ └┘   └─────────────┘  └┘   └───┘ └──┘
src  └─┘    └───┘ └────────┘      └─────────────┘       └───┘ └──┘
typ  └─┘  └┘└───┘ └────────┘ └┘   └─────────────┘  └┘   └───┘ └──┘
620  
621  theorem option_orelse :
622    primrec₂ ((<|>) : option α → option α → option α) :=
id     └──────┘         └────┘    └────┘    └────┘ 
src    └──────┘         └────┘     └────┘     └────┘
typ    └──────┘         └────┘    └────┘    └────┘ 
doc    └──────┘
623  (option_cases fst snd (fst.comp fst).to₂).of_eq $
id    └──────────┘ └─┘ └─┘  └─┘└───┘ └─┘ └─┘  └───┘
src   └──────────┘ └─┘ └─┘  └─┘└───┘ └─┘ └─┘  └───┘
typ   └──────────┘ └─┘ └─┘  └─┘└───┘ └─┘ └─┘  └───┘
624  λ ⟨o₁, o₂⟩, by cases o₁; cases o₂; refl
id                       └┘        └┘
src                 └────┘    └────┘    └────
typ                └────┘└┘  └────┘└┘  └────
doc                 └────┘    └────┘    └────
txt                 └────┘    └────┘    └────
par                 └────┘    └────┘    └────
pid                                       
st                 └─────────────────────────
625  
src  
typ  
doc  
txt  
par  
pid  
st   
626  protected theorem decode2 : primrec (decode2 α) :=
id                               └─────┘  └─────┘ 
src                              └─────┘  └─────┘
typ                              └─────┘  └─────┘ 
doc                              └─────┘
627  option_bind primrec.decode $
id   └─────────┘ └────────────┘
src  └─────────┘ └────────────┘
typ  └─────────┘ └────────────┘
628  option_guard ((@primrec.eq _ _ nat.decidable_eq).comp
id   └──────────┘    └────────┘     └──────────────┘ └──┘
src  └──────────┘    └────────┘     └──────────────┘ └──┘
typ  └──────────┘    └────────┘     └──────────────┘ └──┘
629    (encode_iff.2 snd) (fst.comp fst)) snd
id      └────────┘  └─┘   └─┘└───┘ └─┘   └─┘
src     └────────┘  └─┘   └─┘└───┘ └─┘   └─┘
typ     └────────┘  └─┘   └─┘└───┘ └─┘   └─┘
630  
631  theorem list_find_index₁ {p : α → β → Prop}
id                                    
typ                                   
632    [∀ a b, decidable (p a b)] (hp : primrec_rel p) :
id           └───────┘             └─────────┘ 
src            └───────┘                └─────────┘
typ          └───────┘             └─────────┘ 
doc                                     └─────────┘
633    ∀ (l : list β), primrec (λ a, l.find_index (p a))
id           └──┘    └─────┘      └─────────┘   
src           └──┘     └─────┘        └─────────┘
typ          └──┘    └─────┘      └─────────┘   
doc                    └─────┘
634  | [] := const 0
id     └┘    └───┘
src    └┘    └───┘
typ    └┘    └───┘
635  | (a::l) := ite (hp.comp primrec.id (const a)) (const 0)
id      └┘     └─┘  └┘└───┘ └────────┘  └───┘      └───┘
src      └┘      └─┘    └───┘ └────────┘  └───┘      └───┘
typ     └┘     └─┘  └┘└───┘ └────────┘  └───┘      └───┘
636    (succ.comp (list_find_index₁ l))
id      └──┘└───┘  └──────────────┘
src     └──┘└───┘
typ     └──┘└───┘  └──────────────┘
637  
638  theorem list_index_of₁ [decidable_eq α] (l : list α) :
id                           └──────────┘        └──┘ 
src                          └──────────┘         └──┘
typ                          └──────────┘        └──┘ 
639    primrec (λ a, l.index_of a) := list_find_index₁ primrec.eq l
id     └─────┘      └───────┘      └──────────────┘ └────────┘ 
src    └─────┘        └───────┘       └──────────────┘ └────────┘
typ    └─────┘      └───────┘      └──────────────┘ └────────┘ 
doc    └─────┘
640  
641  theorem dom_fintype [fintype α] (f : α → σ) : primrec f :=
id                        └─────┘               └─────┘ 
src                       └─────┘                  └─────┘
typ                       └─────┘               └─────┘ 
doc                       └─────┘                  └─────┘
642  let ⟨l, nd, m⟩ := fintype.exists_univ_list α in
id   └─┘               └──────────────────────┘ 
src                    └──────────────────────┘
typ  └─┘               └──────────────────────┘ 
643  option_some_iff.1 $ begin
id   └─────────────┘
src  └─────────────┘
typ  └─────────────┘
st                       └─────
644    haveI := decidable_eq_of_encodable α,
id              └───────────────────────┘ 
src    └───────┘└───────────────────────┘
typ    └───────┘└───────────────────────┘
doc    └───────┘                         
txt    └───────┘                         
par    └───────┘                         
pid         └─┘                         
st   ─────────────────────────────────────┘└─
645    refine ((list_nth₁ (l.map f)).comp (list_index_of₁ l)).of_eq (λ a, _),
id              └───────┘  └───┘          └────────────┘ 
src    └─────┘  └───────┘ └───┘ └──────┘ └────────────┘ └───────┘  └────┘
typ    └─────┘  └───────┘ └───┘└──────┘ └────────────┘└───────┘  └────┘
doc    └─────┘                  └──────┘                └───────┘  └────┘
txt    └─────┘                  └──────┘                └───────┘  └────┘
par    └─────┘                  └──────┘                └───────┘  └────┘
pid                            └──────┘                └───────┘  └────┘
st   ──────────────────────────────────────────────────────────────────────┘└─
646    rw [list.nth_map, list.nth_le_nth (list.index_of_lt_length.2 (m _)),
id         └──────────┘  └─────────────┘  └─────────────────────┘    
src    └──┘└──────────┘└┘└─────────────┘ └─────────────────────┘└─┘  └─────
typ    └──┘└──────────┘└┘└─────────────┘ └─────────────────────┘└─┘ └─────
doc    └──┘            └┘                                       └─┘  └─────
txt    └──┘            └┘                                       └─┘  └─────
par    └──┘            └┘                                       └─┘  └─────
pid      └┘            └┘                                       └─┘  └─────
st   ─────────────────┘└─────────────────────────────────────────────────┘└─
647        list.index_of_nth_le]; refl
id         └──────────────────┘
src  ─────┘└──────────────────┘  └───┘
typ  ─────┘└──────────────────┘  └───┘
doc  ─────┘                      └───┘
txt  ─────┘                      └───┘
par  ─────┘                      └───┘
pid  ─────┘                          
st   ─────────────────────────┘└─────┘
648  end
st   └─┘
649  
650  theorem nat_bodd_div2 : primrec nat.bodd_div2 :=
id                           └─────┘ └───────────┘
src                          └─────┘ └───────────┘
typ                          └─────┘ └───────────┘
doc                          └─────┘
651  (nat_elim' primrec.id (const (ff, 0))
id    └───────┘ └────────┘  └───┘ └┘
src   └───────┘ └────────┘  └───┘ └┘
typ   └───────┘ └────────┘  └───┘ └┘
652    (((cond fst
id        └──┘ └─┘
src       └──┘ └─┘
typ       └──┘ └─┘
653        (pair (const ff) (succ.comp snd))
id          └──┘  └───┘ └┘   └──┘└───┘ └─┘
src         └──┘  └───┘ └┘   └──┘└───┘ └─┘
typ         └──┘  └───┘ └┘   └──┘└───┘ └─┘
654        (pair (const tt) snd)).comp snd).comp snd).to₂).of_eq $
id          └──┘  └───┘ └┘  └─┘  └──┘  └─┘ └──┘  └─┘ └─┘  └───┘
src         └──┘  └───┘ └┘  └─┘  └──┘  └─┘ └──┘  └─┘ └─┘  └───┘
typ         └──┘  └───┘ └┘  └─┘  └──┘  └─┘ └──┘  └─┘ └─┘  └───┘
655  λ n, begin
id     
typ    
st        └─────
656    simp [-nat.bodd_div2_eq],
src    └──────────────────────┘
typ    └──────────────────────┘
doc    └──────────────────────┘
txt    └──────────────────────┘
par    └──────────────────────┘
pid        └─────────────────┘
st   ─────────────────────────┘└─
657    induction n with n IH, {refl},
id               
src    └────────┘ └────────┘   └──┘
typ    └────────┘└────────┘   └──┘
doc    └────────┘ └────────┘   └──┘
txt    └────────┘ └────────┘   └──┘
par    └────────┘ └────────┘   └──┘
pid              └───────┘
st   ──────────────────────┘└─────┘└┘
658    simp [-nat.bodd_div2_eq, nat.bodd_div2, *],
id                              └───────────┘
src    └───────────────────────┘└───────────┘└──┘
typ    └───────────────────────┘└───────────┘└──┘
doc    └───────────────────────┘             └──┘
txt    └───────────────────────┘             └──┘
par    └───────────────────────┘             └──┘
pid        └──────────────────┘             └──┘
st   ───────────────────────────────────────────┘└─
659    rcases nat.bodd_div2 n with ⟨_|_, m⟩; simp [nat.bodd_div2]
id            └───────────┘                       └───────────┘
src    └─────┘└───────────┘ └────────────┘  └────┘└───────────┘└┘
typ    └─────┘└───────────┘└────────────┘  └────┘└───────────┘└┘
doc    └─────┘              └────────────┘  └────┘             └┘
txt    └─────┘              └────────────┘  └────┘             └┘
par    └─────┘              └────────────┘  └────┘             └┘
pid                        └────────────┘                   
st   ────────────────────────────────────────────────────────────┘
660  end
st   └─┘
661  
662  theorem nat_bodd : primrec nat.bodd := fst.comp nat_bodd_div2
id                      └─────┘ └──────┘    └─┘└───┘ └───────────┘
src                     └─────┘ └──────┘    └─┘└───┘ └───────────┘
typ                     └─────┘ └──────┘    └─┘└───┘ └───────────┘
doc                     └─────┘
663  theorem nat_div2 : primrec nat.div2 := snd.comp nat_bodd_div2
id                      └─────┘ └──────┘    └─┘└───┘ └───────────┘
src                     └─────┘ └──────┘    └─┘└───┘ └───────────┘
typ                     └─────┘ └──────┘    └─┘└───┘ └───────────┘
doc                     └─────┘
664  
665  theorem nat_bit0 : primrec (@bit0 ℕ _) :=
id                      └─────┘   └──┘ 
src                     └─────┘   └──┘ 
typ                     └─────┘   └──┘ 
doc                     └─────┘
666  nat_add.comp primrec.id primrec.id
id   └─────┘└───┘ └────────┘ └────────┘
src  └─────┘└───┘ └────────┘ └────────┘
typ  └─────┘└───┘ └────────┘ └────────┘
667  
668  theorem nat_bit1 : primrec (@bit1 ℕ _ _) :=
id                      └─────┘   └──┘ 
src                     └─────┘   └──┘ 
typ                     └─────┘   └──┘ 
doc                     └─────┘
669  nat_add.comp nat_bit0 (const 1)
id   └─────┘└───┘ └──────┘  └───┘
src  └─────┘└───┘ └──────┘  └───┘
typ  └─────┘└───┘ └──────┘  └───┘
670  
671  theorem nat_bit : primrec₂ nat.bit :=
id                     └──────┘ └─────┘
src                    └──────┘ └─────┘
typ                    └──────┘ └─────┘
doc                    └──────┘
672  (cond primrec.fst
id    └──┘ └─────────┘
src   └──┘ └─────────┘
typ   └──┘ └─────────┘
673    (nat_bit1.comp primrec.snd)
id      └──────┘└───┘ └─────────┘
src     └──────┘└───┘ └─────────┘
typ     └──────┘└───┘ └─────────┘
674    (nat_bit0.comp primrec.snd)).of_eq $
id      └──────┘└───┘ └─────────┘  └───┘
src     └──────┘└───┘ └─────────┘  └───┘
typ     └──────┘└───┘ └─────────┘  └───┘
675  λ n, by cases n.1; refl
id                
src          └────┘ └┘  └────
typ         └────┘└┘  └────
doc          └────┘ └┘  └────
txt          └────┘ └┘  └────
par          └────┘ └┘  └────
pid                └┘      
st          └────────────────
676  
src  
typ  
doc  
txt  
par  
pid  
st   
677  theorem nat_div_mod : primrec₂ (λ n k : ℕ, (n / k, n % k)) :=
id                         └──────┘                  
src                        └──────┘                    
typ                        └──────┘                  
doc                        └──────┘
678  let f (a : ℕ × ℕ) : ℕ × ℕ := a.1.elim (0, 0) (λ _ IH,
id                           └──┘            └┘
src                           └──┘  
typ                          └──┘            └┘
679    if nat.succ IH.2 = a.2
id        └──────┘ └┘   
src       └──────┘       
typ       └──────┘ └┘   
680    then (nat.succ IH.1, 0)
id          └──────┘ └┘
src         └──────┘   
typ         └──────┘ └┘
681    else (IH.1, nat.succ IH.2)) in
id          └┘   └──────┘ └┘
src              └──────┘   
typ         └┘   └──────┘ └┘
682  have hf : primrec f, from
id             └─────┘ 
src            └─────┘
typ            └─────┘ 
doc            └─────┘
683  nat_elim' fst (const (0, 0)) $
id   └───────┘ └─┘  └───┘ 
src  └───────┘ └─┘  └───┘ 
typ  └───────┘ └─┘  └───┘ 
684    ((ite ((@primrec.eq ℕ _ _).comp (succ.comp $ snd.comp snd) fst)
id       └─┘    └────────┘      └──┘   └──┘└───┘   └─┘└───┘ └─┘  └─┘
src      └─┘    └────────┘      └──┘   └──┘└───┘   └─┘└───┘ └─┘  └─┘
typ      └─┘    └────────┘      └──┘   └──┘└───┘   └─┘└───┘ └─┘  └─┘
685        (pair (succ.comp $ fst.comp snd) (const 0))
id          └──┘  └──┘└───┘   └─┘└───┘ └─┘   └───┘
src         └──┘  └──┘└───┘   └─┘└───┘ └─┘   └───┘
typ         └──┘  └──┘└───┘   └─┘└───┘ └─┘   └───┘
686        (pair (fst.comp snd) (succ.comp $ snd.comp snd)))
id          └──┘  └─┘└───┘ └─┘   └──┘└───┘   └─┘└───┘ └─┘
src         └──┘  └─┘└───┘ └─┘   └──┘└───┘   └─┘└───┘ └─┘
typ         └──┘  └─┘└───┘ └─┘   └──┘└───┘   └─┘└───┘ └─┘
687      .comp (pair (snd.comp fst) (snd.comp snd))).to₂,
id       └──┘   └──┘  └─┘└───┘ └─┘   └─┘└───┘ └─┘   └─┘
src      └──┘   └──┘  └─┘└───┘ └─┘   └─┘└───┘ └─┘   └─┘
typ      └──┘   └──┘  └─┘└───┘ └─┘   └─┘└───┘ └─┘   └─┘
688  suffices ∀ k n, (n / k, n % k) = f (n, k),
id                             
src                                 
typ                            
689  from hf.of_eq $ λ ⟨m, n⟩, by simp [this],
id        └┘└────┘                     └──┘
src         └────┘                └────┘    
typ       └┘└────┘               └────┘└──┘
doc                               └────┘    
txt                               └────┘    
par                               └────┘    
pid                                       
st                               └──────────┘
690  λ k n, begin
id      
typ     
st          └─────
691    have : (f (n, k)).2 + k * (f (n, k)).1 = n
id                                          
src    └─────┘    └┘ └───┘     └┘ └───┘ 
typ    └─────┘    └┘ └───┘     └┘ └───┘ 
doc    └─────┘    └┘ └───┘       └┘ └───┘  
txt    └─────┘    └┘ └───┘       └┘ └───┘  
par    └─────┘    └┘ └───┘       └┘ └───┘  
pid    └───┘└┘    └┘ └───┘       └┘ └───┘  
st   ─────────────────────────────────────────────
692      ∧ (0 < k → (f (n, k)).2 < k)
id           
src  ───┘ └┘      └┘ └───┘  └─
typ  ───┘ └┘      └┘ └───┘  └─
doc  ───┘  └┘       └┘ └───┘  └─
txt  ───┘  └┘       └┘ └───┘  └─
par  ───┘  └┘       └┘ └───┘  └─
pid  ───┘  └┘       └┘ └───┘  └─
st   ─────────────────────────────────
693      ∧ (k = 0 → (f (n, k)).1 = 0),
id                     
src  ───┘    └─┘    └┘ └───┘ └─┘
typ  ───┘   └─┘  └┘└───┘ └─┘
doc  ───┘    └─┘     └┘ └───┘ └─┘
txt  ───┘    └─┘     └┘ └───┘ └─┘
par  ───┘    └─┘     └┘ └───┘ └─┘
pid  ───┘    └─┘     └┘ └───┘ └─┘
st   ───────────────────────────────┘└─
694    { induction n with n IH, {exact ⟨rfl, id, λ _, rfl⟩},
id                                          └┘       └─┘
src      └────────┘ └────────┘   └────┘    └┘└┘└┘ └──┘└─┘
typ      └────────┘└────────┘   └────┘    └┘└┘└┘ └──┘└─┘
doc      └────────┘ └────────┘   └────┘    └┘  └┘ └──┘   
txt      └────────┘ └────────┘   └────┘    └┘  └┘ └──┘   
par      └────────┘ └────────┘   └────┘    └┘  └┘ └──┘   
pid                └───────┘            └┘  └┘ └──┘   
st   ───┘└───────────────────┘└──────────────────────────┘└┘
695      rw [λ n:ℕ, show f (n.succ, k) =
id                           └───┘     
src      └──┘ └─┘ └┘       └───┘└┘ └┘ 
typ      └──┘ └─┘ └┘       └───┘└┘ └┘
doc      └──┘ └─┘ └┘            └┘ └┘ 
txt      └──┘ └─┘ └┘            └┘ └┘ 
par      └──┘ └─┘ └┘            └┘ └┘ 
pid        └┘ └─┘ └┘            └┘ └┘ 
st   ────────────────────────────────────
696        _root_.ite ((f (n, k)).2.succ = k)
id         └────────┘
src  ─────┘└────────┘     └┘ └────────┘  └─
typ  ─────┘└────────┘     └┘ └────────┘  └─
doc  ─────┘               └┘ └────────┘  └─
txt  ─────┘               └┘ └────────┘  └─
par  ─────┘               └┘ └────────┘  └─
pid  ─────┘               └┘ └────────┘  └─
st   ─────────────────────────────────────────
697        (nat.succ (f (n, k)).1, 0)
id          └──────┘
src  ─────┘ └──────┘    └┘ └────────
typ  ─────┘ └──────┘    └┘ └────────
doc  ─────┘             └┘ └────────
txt  ─────┘             └┘ └────────
par  ─────┘             └┘ └────────
pid  ─────┘             └┘ └────────
st   ─────────────────────────────────
698        ((f (n, k)).1, (f (n, k)).2.succ), from rfl],
id                                              └─┘
src  ─────┘     └┘ └────┘   └┘ └───────────────┘└─┘
typ  ─────┘     └┘ └────┘  └┘└───────────────┘└─┘
doc  ─────┘     └┘ └────┘    └┘ └───────────────┘   
txt  ─────┘     └┘ └────┘    └┘ └───────────────┘   
par  ─────┘     └┘ └────┘    └┘ └───────────────┘   
pid  ─────┘     └┘ └────┘    └┘ └───────────────┘   
st   ────────────────────────────────────────────────┘└─
699      by_cases h : (f (n, k)).2.succ = k; simp [h],
id                                             
src      └───────┘ └─┘   └┘ └────────┘    └────┘ 
typ      └───────┘ └─┘ └┘ └────────┘   └────┘
doc      └───────┘ └─┘    └┘ └────────┘    └────┘ 
txt      └───────┘ └─┘    └┘ └────────┘    └────┘ 
par      └───────┘ └─┘    └┘ └────────┘    └────┘ 
pid               └─┘    └┘ └────────┘         
st   ───────────────────────────────────────────────┘└─
700      { have := congr_arg nat.succ IH.1,
id                 └───────┘ └──────┘ └┘
src        └──────┘└───────┘└──────┘  └┘
typ        └──────┘└───────┘└──────┘└┘└┘
doc        └──────┘                   └┘
txt        └──────┘                   └┘
par        └──────┘                   └┘
pid        └───┘└─┘                   └┘
st   ─────┘└─────────────────────────────┘└─
701        refine ⟨_, λ k0, nat.no_confusion (h.trans k0)⟩,
id                          └──────────────┘  └─────┘
src        └─────┘ └─┘ └───┘└──────────────┘ └─────┘  └┘
typ        └─────┘ └─┘ └───┘└──────────────┘ └─────┘  └┘
doc        └─────┘ └─┘ └───┘                          └┘
txt        └─────┘ └─┘ └───┘                          └┘
par        └─────┘ └─┘ └───┘                          └┘
pid               └─┘ └───┘                          └┘
st   ────────────────────────────────────────────────────┘└─
702        rwa [← nat.succ_add, h, add_comm, ← nat.mul_succ] at this },
id                └──────────┘    └──────┘    └──────────┘
src        └─────┘└──────────┘└┘ └┘└──────┘└──┘└──────────┘└────────┘
typ        └─────┘└──────────┘└┘└┘└──────┘└──┘└──────────┘└────────┘
doc        └─────┘            └┘ └┘        └──┘            └────────┘
txt        └─────┘            └┘ └┘        └──┘            └────────┘
par        └─────┘            └┘ └┘        └──┘            └────────┘
pid           └──┘            └┘ └┘        └──┘            └──────┘
st   ────────────────────────┘└─┘└────────┘└──────────────┘└───────┘└┘
703      { exact ⟨by rw [nat.succ_add, IH.1],
id                       └──────────┘  └┘
src        └────┘   └──┘└──────────┘└┘  └─┘└─
typ        └────┘   └──┘└──────────┘└┘└┘└─┘└─
doc        └────┘   └──┘            └┘  └─┘└─
txt        └────┘   └──┘            └┘  └─┘└─
par        └────┘   └──┘            └┘  └─┘└─
pid                └───┘            └┘  └────
st   ──────────────┘└───────────────┘└──┘└─┘└─
704          λ k0, lt_of_le_of_ne (IH.2.1 k0) h, IH.2.2⟩ } },
id                 └────────────┘               └┘
src  ───────┘ └───┘└────────────┘   └───┘  └┘ └┘  └────┘
typ  ───────┘ └───┘└────────────┘   └───┘  └┘└┘└┘└────┘
doc  ───────┘ └───┘                 └───┘  └┘ └┘  └────┘
txt  ───────┘ └───┘                 └───┘  └┘ └┘  └────┘
par  ───────┘ └───┘                 └───┘  └┘ └┘  └────┘
pid  ───────┘ └───┘                 └───┘  └┘ └┘  └───┘
st   ───────────────────────────────────────────────────┘└──┘
705    revert this, cases f (n, k) with D M,
id                           
src    └─────────┘  └────┘  └┘ └────────┘
typ    └─────────┘  └────┘└┘└────────┘
doc    └─────────┘  └────┘   └┘ └────────┘
txt    └─────────┘  └────┘   └┘ └────────┘
par    └─────────┘  └────┘   └┘ └────────┘
pid          └───┘          └┘ └───────┘
st   ────────────┘└───────────────────────┘└─
706    simp, intros h₁ h₂ h₃,
src    └──┘  └─────────────┘
typ    └──┘  └─────────────┘
doc    └──┘  └─────────────┘
txt    └──┘  └─────────────┘
par    └──┘  └─────────────┘
pid                └───────┘
st   ─────┘└───────────────┘└─
707    cases nat.eq_zero_or_pos k,
id           └────────────────┘ 
src    └────┘└────────────────┘
typ    └────┘└────────────────┘
doc    └────┘                  
txt    └────┘                  
par    └────┘                  
pid                           
st   ───────────────────────────┘└─
708    { simp [h, h₃ h] at h₁ ⊢, simp [h₁] },
id               └┘                  └┘
src      └────┘ └┘   └───────┘  └────┘  └┘
typ      └────┘└┘└┘└───────┘  └────┘└┘└┘
doc      └────┘ └┘   └───────┘  └────┘  └┘
txt      └────┘ └┘   └───────┘  └────┘  └┘
par      └────┘ └┘   └───────┘  └────┘  └┘
pid           └┘   └─────┘        
st   ───┘└────────────────────┘└──────────┘└┘
709    { exact (nat.div_mod_unique h).2 ⟨h₁, h₂ h⟩ }
id              └────────────────┘       └┘  └┘ 
src      └────┘ └────────────────┘ └──┘   └┘   └┘
typ      └────┘ └────────────────┘ └──┘ └┘└┘└┘└┘
doc      └────┘                    └──┘   └┘   └┘
txt      └────┘                    └──┘   └┘   └┘
par      └────┘                    └──┘   └┘   └┘
pid                               └──┘   └┘   
st   ─────────────────────────────────────────────┘└─
710  end
st   ──┘
711  
712  theorem nat_div : primrec₂ ((/) : ℕ → ℕ → ℕ) := fst.comp₂ nat_div_mod
id                     └──────┘                  └─┘└────┘ └─────────┘
src                    └──────┘                  └─┘└────┘ └─────────┘
typ                    └──────┘                  └─┘└────┘ └─────────┘
doc                    └──────┘
713  theorem nat_mod : primrec₂ ((%) : ℕ → ℕ → ℕ) := snd.comp₂ nat_div_mod
id                     └──────┘                  └─┘└────┘ └─────────┘
src                    └──────┘                  └─┘└────┘ └─────────┘
typ                    └──────┘                  └─┘└────┘ └─────────┘
doc                    └──────┘
714  
715  end primrec
716  
717  section
718  variables {α : Type*} {β : Type*} {σ : Type*}
id                        
typ                       
719  variables [primcodable α] [primcodable β] [primcodable σ]
id              └─────────┘    └─────────┘     └─────────┘
src             └─────────┘     └─────────┘     └─────────┘
typ             └─────────┘    └─────────┘     └─────────┘
doc             └─────────┘     └─────────┘     └─────────┘
720  
721  variable (H : nat.primrec (λ n, encodable.encode (decode (list β) n)))
id                 └─────────┘      └──────────────┘  └────┘  └──┘    
src                └─────────┘       └──────────────┘  └────┘  └──┘
typ                └─────────┘      └──────────────┘  └────┘  └──┘    
doc                └─────────┘
722  include H
723  open primrec
724  
725  private def prim : primcodable (list β) := ⟨H⟩
id                      └─────────┘  └──┘       
src                     └─────────┘  └──┘
typ                     └─────────┘  └──┘       
doc                     └─────────┘
726  
727  private lemma list_cases'
728    {f : α → list β} {g : α → σ} {h : α → β × list β → σ}
id             └──┘                       └──┘    
src             └──┘                            └──┘
typ            └──┘                       └──┘    
729    (hf : by haveI := prim H; exact primrec f) (hg : primrec g)
id                       └──┘         └─────┘         └─────┘ 
src             └───────┘└──┘   └────┘└─────┘         └─────┘
typ             └───────┘└──┘  └────┘└─────┘        └─────┘ 
doc             └───────┘       └────┘└─────┘         └─────┘
txt             └───────┘       └────┘       
par             └───────┘       └────┘       
pid                  └─┘                   
st             └───────────────────────────────┘
730    (hh : by haveI := prim H; exact primrec₂ h) :
id                       └──┘         └──────┘ 
src             └───────┘└──┘   └────┘└──────┘
typ             └───────┘└──┘  └────┘└──────┘
doc             └───────┘       └────┘└──────┘
txt             └───────┘       └────┘        
par             └───────┘       └────┘        
pid                  └─┘                    
st             └────────────────────────────────┘
731    @primrec _ σ _ _ (λ a, list.cases_on (f a) (g a) (λ b l, h a (b, l))) :=
id      └─────┘             └───────────┘                   
src     └─────┘               └───────────┘                         
typ     └─────┘             └───────────┘                   
doc     └─────┘
732  by letI := prim H; exact
id              └──┘ 
src     └──────┘└──┘   └────┘
typ     └──────┘└──┘  └────┘
doc     └──────┘       └────┘
txt     └──────┘       └────┘
par     └──────┘       └────┘
pid         └─┘            
st     └──────────────────────
733  have @primrec _ (option σ) _ _ (λ a,
id         └─────┘           
src       └─────┘└─┘        └────┘  └───
typ       └─────┘└─┘       └────┘  └───
doc       └─────┘└─┘        └────┘  └───
txt              └─┘        └────┘  └───
par              └─┘        └────┘  └───
pid              └─┘        └────┘  └───
st   ─────────────────────────────────────
734    (decode (option (β × list β)) (encode (f a))).map
id      └────┘                       └────┘  
src  ─┘ └────┘              └─┘ └────┘   └───────
typ  ─┘ └────┘              └─┘ └────┘  └───────
doc  ─┘                      └─┘          └───────
txt  ─┘                      └─┘          └───────
par  ─┘                      └─┘          └───────
pid  ─┘                      └─┘          └───────
st   ────────────────────────────────────────────────────
735    (λ o, option.cases_on o (g a) (h a))), from
id           └─────────────┘         
src  ─┘  └──┘└─────────────┘    └┘   └────────┘
typ  ─┘  └──┘└─────────────┘   └┘  └────────┘
doc  ─┘  └──┘                   └┘   └────────┘
txt  ─┘  └──┘                   └┘   └────────┘
par  ─┘  └──┘                   └┘   └────────┘
pid  ─┘  └──┘                   └┘   └────────┘
st   ──────────────────────────────────────────────
736  ((@map_decode_iff _ (option (β × list β)) _ _ _ _ _).2 $
id      └────────────┘    └────┘      └──┘ 
src     └────────────┘└─┘ └────┘   └──┘ └──────────────┘ 
typ     └────────────┘└─┘ └────┘   └──┘└──────────────┘ 
doc                   └─┘               └──────────────┘ 
txt                   └─┘               └──────────────┘ 
par                   └─┘               └──────────────┘ 
pid                   └─┘               └──────────────┘ 
st   ─────────────────────────────────────────────────────────
737      to₂ $ option_cases snd (hg.comp fst)
id       └─┘   └──────────┘ └─┘  └─────┘
src  ───┘└─┘ └──────────┘└─┘ └─────┘   └─
typ  ───┘└─┘ └──────────┘└─┘ └─────┘   └─
doc  ───┘                              └─
txt  ───┘                              └─
par  ───┘                              └─
pid  ───┘                              └─
st   ─────────────────────────────────────────
738    (hh.comp₂ (fst.comp₂ primrec₂.left) primrec₂.right))
id      └──────┘  └───────┘ └───────────┘  └────────────┘
src  ─┘ └──────┘ └───────┘└───────────┘└┘└────────────┘└──
typ  ─┘ └──────┘ └───────┘└───────────┘└┘└────────────┘└──
doc  ─┘                                └┘              └──
txt  ─┘                                └┘              └──
par  ─┘                                └┘              └──
pid  ─┘                                └┘              └──
st   ───────────────────────────────────────────────────────
739      .comp primrec.id (encode_iff.2 hf),
id             └────────┘  └────────┘   └┘
src  ─────────┘└────────┘ └────────┘└─┘  └─┘
typ  ─────────┘└────────┘ └────────┘└─┘└┘└─┘
doc  ─────────┘                     └─┘  └─┘
txt  ─────────┘                     └─┘  └─┘
par  ─────────┘                     └─┘  └─┘
pid  ─────────┘                     └─┘  └─┘
st   ────────────────────────────────────────
740  option_some_iff.1 $ this.of_eq $
id   └─────────────┘         └────┘
src  └─────────────┘└─┘     └────┘ 
typ  └─────────────┘└─┘     └────┘ 
doc                 └─┘            
txt                 └─┘            
par                 └─┘            
pid                 └─┘            
st   ─────────────────────────────────
741  λ a, by cases f a with b l; simp [encodek]; refl
id                                   └─────┘
src   └──┘  └────┘  └───────┘└┘└────┘└─────┘└┘└────
typ   └──┘  └────┘└───────┘└┘└────┘└─────┘└┘└────
doc   └──┘  └────┘  └───────┘└┘└────┘       └┘└────
txt   └──┘  └────┘  └───────┘└┘└────┘       └┘└────
par   └──┘  └────┘  └───────┘└┘└────┘       └┘└────
pid   └──┘  └─────┘  └───────────────┘       └───────
st   ──────┘└─────────────────────────────────────────
742  
src  
typ  
doc  
txt  
par  
pid  
st   
743  private lemma list_foldl'
744    {f : α → list β} {g : α → σ} {h : α → σ × β → σ}
id             └──┘                          
src             └──┘                           
typ            └──┘                          
745    (hf : by haveI := prim H; exact primrec f) (hg : primrec g)
id                       └──┘         └─────┘         └─────┘ 
src             └───────┘└──┘   └────┘└─────┘         └─────┘
typ             └───────┘└──┘  └────┘└─────┘        └─────┘ 
doc             └───────┘       └────┘└─────┘         └─────┘
txt             └───────┘       └────┘       
par             └───────┘       └────┘       
pid                  └─┘                   
st             └───────────────────────────────┘
746    (hh : by haveI := prim H; exact primrec₂ h) :
id                       └──┘         └──────┘ 
src             └───────┘└──┘   └────┘└──────┘
typ             └───────┘└──┘  └────┘└──────┘
doc             └───────┘       └────┘└──────┘
txt             └───────┘       └────┘        
par             └───────┘       └────┘        
pid                  └─┘                    
st             └────────────────────────────────┘
747    primrec (λ a, (f a).foldl (λ s b, h a (s, b)) (g a)) :=
id     └─────┘         └───┘                 
src    └─────┘            └───┘              
typ    └─────┘         └───┘                 
doc    └─────┘
748  by letI := prim H; exact
id              └──┘ 
src     └──────┘└──┘   └────┘
typ     └──────┘└──┘  └────┘
doc     └──────┘       └────┘
txt     └──────┘       └────┘
par     └──────┘       └────┘
pid         └─┘            
st     └──────────────────────
749  let G (a : α) (IH : σ × list β) : σ × list β :=
id                                      └──┘ 
src     └──────┘ └──────┘      └──┘  └──┘ └───
typ     └──────┘ └──────┘      └──┘└──┘└───
doc     └──────┘ └──────┘       └──┘       └───
txt     └──────┘ └──────┘       └──┘       └───
par     └──────┘ └──────┘       └──┘       └───
pid     └──────┘ └──────┘       └──┘       └───
st   ────────────────────────────────────────────────
750    list.cases_on IH.2 IH (λ b l, (h a (IH.1, b), l)) in
id     └───────────┘                 
src  ─┘└───────────┘  └─┘    └────┘     └──┘ └─┘ └────┘
typ  ─┘└───────────┘  └─┘    └────┘    └──┘ └─┘ └────┘
doc  ─┘               └─┘    └────┘      └──┘ └─┘ └────┘
txt  ─┘               └─┘    └────┘      └──┘ └─┘ └────┘
par  ─┘               └─┘    └────┘      └──┘ └─┘ └────┘
pid  ─┘               └─┘    └────┘      └──┘ └─┘ └────┘
st   ───────────────────────────────────────────────────────
751  let F (a : α) (n : ℕ) := nat.iterate (G a) n (g a, f a) in
id                           └─────────┘          
src     └──────┘ └─────┘ └───┘└─────────┘   └┘    └┘  └───┘
typ     └──────┘└─────┘ └───┘└─────────┘   └┘   └┘  └───┘
doc     └──────┘ └─────┘ └───┘              └┘    └┘  └───┘
txt     └──────┘ └─────┘ └───┘              └┘    └┘  └───┘
par     └──────┘ └─────┘ └───┘              └┘    └┘  └───┘
pid     └──────┘ └─────┘ └───┘              └┘    └┘  └───┘
st   ───────────────────────────────────────────────────────────
752  have primrec (λ a, (F a (encode (f a))).1), from
id                            └────┘  
src      └───────┘  └──┘    └────┘   └───────────┘
typ      └───────┘  └──┘    └────┘  └───────────┘
doc      └───────┘  └──┘             └───────────┘
txt      └───────┘  └──┘             └───────────┘
par      └───────┘  └──┘             └───────────┘
pid      └───────┘  └──┘             └───────────┘
st   ─────────────────────────────────────────────────
753  fst.comp $ nat_iterate (encode_iff.2 hf) (pair hg hf) $
id              └─────────┘  └────────┘             └┘ └┘
src           └─────────┘ └────────┘└─┘  └┘         └┘ 
typ           └─────────┘ └────────┘└─┘  └┘     └┘└┘└┘ 
doc                                 └─┘  └┘         └┘ 
txt                                 └─┘  └┘         └┘ 
par                                 └─┘  └┘         └┘ 
pid                                 └─┘  └┘         └┘ 
st   ────────────────────────────────────────────────────────
754    list_cases' H (snd.comp snd) snd $ to₂ $ pair
id     └─────────┘                       └─┘
src  ─┘└─────────┘             └┘    └─┘     
typ  ─┘└─────────┘            └┘    └─┘     
doc  ─┘                        └┘            
txt  ─┘                        └┘            
par  ─┘                        └┘            
pid  ─┘                        └┘            
st   ────────────────────────────────────────────────
755      (hh.comp (fst.comp fst) $
id        └─────┘
src  ───┘ └─────┘            └┘ 
typ  ───┘ └─────┘            └┘ 
doc  ───┘                    └┘ 
txt  ───┘                    └┘ 
par  ───┘                    └┘ 
pid  ───┘                    └┘ 
st   ──────────────────────────────
756        pair ((fst.comp snd).comp fst) (fst.comp snd))
id         └──┘                            └──────┘
src  ─────┘└──┘             └─────┘   └┘ └──────┘   └──
typ  ─────┘└──┘             └─────┘   └┘ └──────┘   └──
doc  ─────┘                 └─────┘   └┘            └──
txt  ─────┘                 └─────┘   └┘            └──
par  ─────┘                 └─────┘   └┘            └──
pid  ─────┘                 └─────┘   └┘            └──
st   ─────────────────────────────────────────────────────
757      (snd.comp snd),
id        └──────┘ └─┘
src  ───┘ └──────┘└─┘└─┘
typ  ───┘ └──────┘└─┘└─┘
doc  ───┘            └─┘
txt  ───┘            └─┘
par  ───┘            └─┘
pid  ───┘            └─┘
st   ────────────────────
758  this.of_eq $ λ a, begin
id       └────┘
src      └────┘  └──┘     
typ      └────┘  └──┘     
doc              └──┘     
txt              └──┘     
par              └──┘     
pid              └──┘     
st   ─────────────────┘└─────
759    have : ∀ n, F a n =
id                      
src  ─┘└─────┘ └┘    
typ  ─┘└─────┘ └┘   
doc  ─┘└─────┘ └┘     
txt  ─┘└─────┘ └┘     
par  ─┘└─────┘ └┘     
pid  ────────┘ └┘     
st   ──────────────────────
760      ((list.take n (f a)).foldl (λ s b, h a (s, b)) (g a),
id         └───────┘                                   
src  ───┘  └───────┘    └───────┘  └────┘   └┘ └─┘   └──
typ  ───┘  └───────┘    └───────┘  └────┘  └┘ └─┘  └──
doc  ───┘               └───────┘  └────┘    └┘ └─┘   └──
txt  ───┘               └───────┘  └────┘    └┘ └─┘   └──
par  ───┘               └───────┘  └────┘    └┘ └─┘   └──
pid  ───┘               └───────┘  └────┘    └┘ └─┘   └──
st   ──────────────────────────────────────────────────────────
761        list.drop n (f a)),
id         └───────┘     
src  ─────┘└───────┘    └┘└─
typ  ─────┘└───────┘  └┘└─
doc  ─────┘             └┘└─
txt  ─────┘             └┘└─
par  ─────┘             └┘└─
pid  ─────┘             └───
st   ───────────────────────┘└─
762    { intro, simp [F],
id                    
src  ───┘└───┘└┘└────┘ └─
typ  ───┘└───┘└┘└────┘└─
doc  ───┘└───┘└┘└────┘ └─
txt  ───┘└───┘└┘└────┘ └─
par  ───┘└───┘└┘└────┘ └─
pid  ────────────────┘ └──
st   ──┘└────┘└────────┘└─
763      generalize : f a = l, generalize : g a = x,
id                                         
src  ───┘└───────────┘    └┘└───────────┘    └─
typ  ───┘└───────────┘  └┘└───────────┘  └─
doc  ───┘└───────────┘    └┘└───────────┘    └─
txt  ───┘└───────────┘    └┘└───────────┘    └─
par  ───┘└───────────┘    └┘└───────────┘    └─
pid  ────────────────┘    └─────────────┘    └─
st   ───────────────────────┘└────────────────────┘└─
764      induction n with n IH generalizing l x, {refl},
id                 
src  ───┘└────────┘ └─────────────────────────┘└─┘└──┘└──
typ  ───┘└────────┘└─────────────────────────┘└─┘└──┘└──
doc  ───┘└────────┘ └─────────────────────────┘└─┘└──┘└──
txt  ───┘└────────┘ └─────────────────────────┘└─┘└──┘└──
par  ───┘└────────┘ └─────────────────────────┘└─┘└──┘└──
pid  ─────────────┘ └────────────────────────────────────
st   ─────────────────────────────────────────┘└─────┘└─
765      simp, cases l with b l; simp [IH] },
id                                    └┘
src  ───┘└──┘└┘└────┘ └───────┘└┘└────┘  └┘└──
typ  ───┘└──┘└┘└────┘└───────┘└┘└────┘└┘└┘└──
doc  ───┘└──┘└┘└────┘ └───────┘└┘└────┘  └┘└──
txt  ───┘└──┘└┘└────┘ └───────┘└┘└────┘  └┘└──
par  ───┘└──┘└┘└────┘ └───────┘└┘└────┘  └┘└──
pid  ───────────────┘ └───────────────┘  └────
st   ───────┘└────────────────────────────┘└─
766    rw [this, list.take_all_of_le (length_le_encode _)]
id         └──┘  └─────────────────┘  └──────────────┘
src  ─┘└──┘    └┘└─────────────────┘ └──────────────┘└───┘
typ  ─┘└──┘└──┘└┘└─────────────────┘ └──────────────┘└───┘
doc  ─┘└──┘    └┘                                    └───┘
txt  ─┘└──┘    └┘                                    └───┘
par  ─┘└──┘    └┘                                    └───┘
pid  ─────┘    └┘                                    └────
st   ─────────┘└────────────────────────────────────────┘
767  end
src  └───
typ  └───
doc  └───
txt  └───
par  └───
pid  ──┘
st   └─┘
768  
src  
typ  
doc  
txt  
par  
pid  
st   
769  private lemma list_cons' : by haveI := prim H; exact primrec₂ (@list.cons β) :=
id                                          └──┘         └──────┘   └───────┘ 
src                                └───────┘└──┘   └────┘└──────┘  └───────┘ └┘
typ                                └───────┘└──┘  └────┘└──────┘  └───────┘└┘
doc                                └───────┘       └────┘└──────┘            └┘
txt                                └───────┘       └────┘                    └┘
par                                └───────┘       └────┘                    └┘
pid                                     └─┘                                
st                                └──────────────────────────────────────────────┘
770  by letI := prim H; exact
id              └──┘ 
src     └──────┘└──┘   └────┘
typ     └──────┘└──┘  └────┘
doc     └──────┘       └────┘
txt     └──────┘       └────┘
par     └──────┘       └────┘
pid         └─┘            
st     └──────────────────────
771  encode_iff.1 (succ.comp $
id                 └───────┘
src            └─┘ └───────┘ 
typ            └─┘ └───────┘ 
doc            └─┘           
txt            └─┘           
par            └─┘           
pid            └─┘           
st   ──────────────────────────
772  primrec₂.mkpair.comp (encode_iff.2 fst) (encode_iff.2 snd))
id   └──────────────────┘               └─┘   └────────┘   └─┘
src  └──────────────────┘           └─┘└─┘└┘ └────────┘└─┘└─┘└──
typ  └──────────────────┘           └─┘└─┘└┘ └────────┘└─┘└─┘└──
doc                                 └─┘   └┘           └─┘   └──
txt                                 └─┘   └┘           └─┘   └──
par                                 └─┘   └┘           └─┘   └──
pid                                 └─┘   └┘           └─┘   └┘
st   ────────────────────────────────────────────────────────────
773  
src  
typ  
doc  
txt  
par  
pid  
st   
774  private lemma list_reverse' : by haveI := prim H; exact
id                                             └──┘ 
src                                   └───────┘└──┘   └─────
typ                                   └───────┘└──┘  └─────
doc                                   └───────┘       └─────
txt                                   └───────┘       └─────
par                                   └───────┘       └─────
pid                                        └─┘            
st                                   └───────────────────────
775    primrec (@list.reverse β) :=
id     └─────┘   └──────────┘ 
src  ─┘└─────┘  └──────────┘ └┘
typ  ─┘└─────┘  └──────────┘└┘
doc  ─┘└─────┘               └┘
txt  ─┘                      └┘
par  ─┘                      └┘
pid  ─┘                      
st   ───────────────────────────┘
776  by letI := prim H; exact
id              └──┘ 
src     └──────┘└──┘   └────┘
typ     └──────┘└──┘  └────┘
doc     └──────┘       └────┘
txt     └──────┘       └────┘
par     └──────┘       └────┘
pid         └─┘            
st     └──────────────────────
777  (list_foldl' H primrec.id (const []) $ to₂ $
id    └─────────┘   └────────┘  └───┘ └┘    └─┘
src   └─────────┘ └────────┘ └───┘└┘└┘ └─┘ 
typ   └─────────┘ └────────┘ └───┘└┘└┘ └─┘ 
doc                                 └┘     
txt                                 └┘     
par                                 └┘     
pid                                 └┘     
st   ─────────────────────────────────────────────
778     ((list_cons' H).comp snd fst).comp snd).of_eq
id        └────────┘            └─┘       └─┘
src  ──┘  └────────┘ └─────┘   └─┘└─────┘└─┘└──────┘
typ  ──┘  └────────┘└─────┘   └─┘└─────┘└─┘└──────┘
doc  ──┘             └─────┘      └─────┘   └──────┘
txt  ──┘             └─────┘      └─────┘   └──────┘
par  ──┘             └─────┘      └─────┘   └──────┘
pid  ──┘             └─────┘      └─────┘   └──────┘
st   ─────────────────────────────────────────────────
779  (suffices ∀ l r, list.foldl (λ (s : list β) (b : β), b :: s) r l = list.reverse_core l r,
id                    └────────┘         └──┘              └┘         └───────────────┘
src            └──┘ └────────┘  └────┘└──┘ └─────┘ └─┘ └┘ └┘  └───────────────┘  └─
typ            └──┘ └────────┘  └────┘└──┘ └─────┘└─┘ └┘ └┘  └───────────────┘  └─
doc            └──┘             └────┘     └─────┘ └─┘    └┘                      └─
txt            └──┘             └────┘     └─────┘ └─┘    └┘                      └─
par            └──┘             └────┘     └─────┘ └─┘    └┘                      └─
pid            └──┘             └────┘     └─────┘ └─┘    └┘                      └─
st   ──────────────────────────────────────────────────────────────────────────────────────────
780  from λ l, this l [],
src  ────┘ └──┘       └┘
typ  ────┘ └──┘       └┘
doc  ────┘ └──┘       └┘
txt  ────┘ └──┘       └┘
par  ────┘ └──┘       └┘
pid  ────┘ └──┘       └┘
st   ─────────────────────
781  λ l, by induction l; simp [*, list.reverse_core])
id                                └───────────────┘
src   └──┘  └────────┘ └┘└───────┘└───────────────┘└─
typ   └──┘  └────────┘└┘└───────┘└───────────────┘└─
doc   └──┘  └────────┘ └┘└───────┘                 └─
txt   └──┘  └────────┘ └┘└───────┘                 └─
par   └──┘  └────────┘ └┘└───────┘                 └─
pid   └──┘  └─────────┘ └─────────┘                 └┘
st   ──────┘└───────────────────────────────────────┘└─
782  
src  
typ  
doc  
txt  
par  
pid  
st   
783  end
784  
785  namespace primcodable
786  variables {α : Type*} {β : Type*}
id             
typ            
787  variables [primcodable α] [primcodable β]
id              └─────────┘     └─────────┘
src             └─────────┘     └─────────┘
typ             └─────────┘     └─────────┘
doc             └─────────┘     └─────────┘
788  open primrec
789  
790  instance sum : primcodable (α ⊕ β) :=
id                  └─────────┘    
src                 └─────────┘    
typ                 └─────────┘    
doc                 └─────────┘
791  ⟨primrec.nat_iff.1 $
id    └─────────────┘
src   └─────────────┘
typ   └─────────────┘
792  (encode_iff.2 (cond nat_bodd
id    └────────┘   └──┘ └──────┘
src   └────────┘   └──┘ └──────┘
typ   └────────┘   └──┘ └──────┘
793    (((@primrec.decode β _).comp nat_div2).option_map $ to₂ $
id         └────────────┘    └──┘  └──────┘ └────────┘   └─┘
src        └────────────┘     └──┘  └──────┘ └────────┘    └─┘
typ        └────────────┘    └──┘  └──────┘ └────────┘   └─┘
794       nat_bit.comp (const tt) (primrec.encode.comp snd))
id        └─────┘└───┘  └───┘ └┘   └────────────┘└───┘ └─┘
src       └─────┘└───┘  └───┘ └┘   └────────────┘└───┘ └─┘
typ       └─────┘└───┘  └───┘ └┘   └────────────┘└───┘ └─┘
795    (((@primrec.decode α _).comp nat_div2).option_map $ to₂ $
id         └────────────┘    └──┘  └──────┘ └────────┘    └─┘
src        └────────────┘     └──┘  └──────┘ └────────┘    └─┘
typ        └────────────┘    └──┘  └──────┘ └────────┘    └─┘
796       nat_bit.comp (const ff) (primrec.encode.comp snd)))).of_eq $
id        └─────┘└───┘  └───┘ └┘   └────────────┘└───┘ └─┘    └───┘
src       └─────┘└───┘  └───┘ └┘   └────────────┘└───┘ └─┘    └───┘
typ       └─────┘└───┘  └───┘ └┘   └────────────┘└───┘ └─┘    └───┘
797  λ n, show _ = encode (decode_sum n), begin
id               └────┘  └────────┘ 
src               └────┘  └────────┘
typ              └────┘  └────────┘ 
st                                        └─────
798    simp [decode_sum],
id           └────────┘
src    └────┘└────────┘
typ    └────┘└────────┘
doc    └────┘          
txt    └────┘          
par    └────┘          
pid                  
st   ──────────────────┘└─
799    cases nat.bodd n; simp [decode_sum],
id           └──────┘         └────────┘
src    └────┘└──────┘   └────┘└────────┘
typ    └────┘└──────┘  └────┘└────────┘
doc    └────┘           └────┘          
txt    └────┘           └────┘          
par    └────┘           └────┘          
pid                                  
st   ────────────────────────────────────┘└─
800    { cases decode α n.div2; refl },
id             └────┘  └────┘
src      └────┘└────┘ └────┘  └───┘
typ      └────┘└────┘└────┘  └───┘
doc      └────┘               └───┘
txt      └────┘               └───┘
par      └────┘               └───┘
pid                              
st   ───┘└──────────────────────────┘└┘
801    { cases decode β n.div2; refl }
id             └────┘  └────┘
src      └────┘└────┘ └────┘  └───┘
typ      └────┘└────┘└────┘  └───┘
doc      └────┘               └───┘
txt      └────┘               └───┘
par      └────┘               └───┘
pid                              
st   ───────────────────────────────┘└─
802  end⟩
st   ──┘
803  
804  instance list : primcodable (list α) := ⟨
id                   └─────────┘  └──┘ 
src                  └─────────┘  └──┘
typ                  └─────────┘  └──┘ 
doc                  └─────────┘
805  by letI H := primcodable.prim (list ℕ); exact
id                └──────────────┘  └──┘
src     └────────┘└──────────────┘ └──┘   └────┘
typ     └────────┘└──────────────┘ └──┘   └────┘
doc     └────────┘                        └────┘
txt     └────────┘                        └────┘
par     └────────┘                        └────┘
pid         └┘└─┘                             
st     └───────────────────────────────────────────
806  have primrec₂ (λ (a : α) (o : option (list ℕ)),
id                                 └────┘
src      └────────┘  └────┘ └─────┘└────┘      └───
typ      └────────┘  └────┘ └─────┘└────┘      └───
doc      └────────┘  └────┘ └─────┘            └───
txt      └────────┘  └────┘ └─────┘            └───
par      └────────┘  └────┘ └─────┘            └───
pid      └────────┘  └────┘ └─────┘            └───
st   ────────────────────────────────────────────────
807    o.map (list.cons (encode a))), from
id      └──┘
src  ─┘ └──┘                  └────────┘
typ  ─┘ └──┘                  └────────┘
doc  ─┘                       └────────┘
txt  ─┘                       └────────┘
par  ─┘                       └────────┘
pid  ─┘                       └────────┘
st   ──────────────────────────────────────
808  option_map snd $
id   └────────┘
src  └────────┘    
typ  └────────┘    
doc                
txt                
par                
pid                
st   ─────────────────
809    (list_cons' H).comp ((@primrec.encode α _).comp (fst.comp fst)) snd,
id      └────────┘           └────────────┘           └──────┘ └─┘   └─┘
src  ─┘ └────────┘ └─────┘   └────────────┘ └───────┘ └──────┘└─┘└─┘└─┘└┘
typ  ─┘ └────────┘└─────┘   └────────────┘└───────┘ └──────┘└─┘└─┘└─┘└┘
doc  ─┘            └─────┘                  └───────┘            └─┘   └┘
txt  ─┘            └─────┘                  └───────┘            └─┘   └┘
par  ─┘            └─────┘                  └───────┘            └─┘   └┘
pid  ─┘            └─────┘                  └───────┘            └─┘   └┘
st   ───────────────────────────────────────────────────────────────────────
810  have primrec (λ n, (of_nat (list ℕ) n).reverse.foldl
id                       └────┘
src      └───────┘  └──┘ └────┘      └┘ └───────────────
typ      └───────┘  └──┘ └────┘      └┘ └───────────────
doc      └───────┘  └──┘             └┘ └───────────────
txt      └───────┘  └──┘             └┘ └───────────────
par      └───────┘  └──┘             └┘ └───────────────
pid      └───────┘  └──┘             └┘ └───────────────
st   ─────────────────────────────────────────────────────
811    (λ o m, (decode α m).bind (λ a, o.map (list.cons (encode a))))
id              └────┘                  └──┘  └───────┘  └────┘
src  ─┘  └────┘ └────┘  └─────┘  └──┘ └──┘ └───────┘ └────┘ └────
typ  ─┘  └────┘ └────┘  └─────┘  └──┘ └──┘ └───────┘ └────┘ └────
doc  ─┘  └────┘         └─────┘  └──┘                       └────
txt  ─┘  └────┘         └─────┘  └──┘                       └────
par  ─┘  └────┘         └─────┘  └──┘                       └────
pid  ─┘  └────┘         └─────┘  └──┘                       └────
st   ─────────────────────────────────────────────────────────────────
812     (some [])), from
id            └┘
src  ──┘     └┘└───────┘
typ  ──┘     └┘└───────┘
doc  ──┘       └───────┘
txt  ──┘       └───────┘
par  ──┘       └───────┘
pid  ──┘       └───────┘
st   ────────────────────
813  list_foldl' H
id   └─────────┘
src  └─────────┘ 
typ  └─────────┘ 
doc              
txt              
par              
pid              
st   ──────────────
814    ((list_reverse' H).comp (primrec.of_nat (list ℕ)))
id       └───────────┘          └────────────┘  └──┘
src  ─┘  └───────────┘ └─────┘ └────────────┘ └──┘ └───
typ  ─┘  └───────────┘ └─────┘ └────────────┘ └──┘ └───
doc  ─┘                └─────┘                     └───
txt  ─┘                └─────┘                     └───
par  ─┘                └─────┘                     └───
pid  ─┘                └─────┘                     └───
st   ─────────────────────────────────────────────────────
815    (const (some []))
id      └───┘  └──┘
src  ─┘ └───┘ └──┘  └──
typ  ─┘ └───┘ └──┘  └──
doc  ─┘             └──
txt  ─┘             └──
par  ─┘             └──
pid  ─┘             └──
st   ────────────────────
816    (primrec.comp₂ (bind_decode_iff.2 $ primrec₂.swap this) primrec₂.right),
id      └───────────┘  └─────────────┘     └───────────┘       └────────────┘
src  ─┘ └───────────┘ └─────────────┘└─┘ └───────────┘    └┘└────────────┘└─┘
typ  ─┘ └───────────┘ └─────────────┘└─┘ └───────────┘    └┘└────────────┘└─┘
doc  ─┘                              └─┘                  └┘              └─┘
txt  ─┘                              └─┘                  └┘              └─┘
par  ─┘                              └─┘                  └┘              └─┘
pid  ─┘                              └─┘                  └┘              └─┘
st   ───────────────────────────────────────────────────────────────────────────
817  nat_iff.1 $ (encode_iff.2 this).of_eq $ λ n, begin
id   └─────┘      └────────┘
src  └─────┘└─┘  └────────┘└─┘    └──────┘  └──┘     
typ  └─────┘└─┘  └────────┘└─┘    └──────┘  └──┘     
doc         └─┘            └─┘    └──────┘  └──┘     
txt         └─┘            └─┘    └──────┘  └──┘     
par         └─┘            └─┘    └──────┘  └──┘     
pid         └─┘            └─┘    └──────┘  └──┘     
st   ────────────────────────────────────────────┘└─────
818    rw list.foldl_reverse,
id        └────────────────┘
src  ─┘└─┘└────────────────┘└─
typ  ─┘└─┘└────────────────┘└─
doc  ─┘└─┘                  └─
txt  ─┘└─┘                  └─
par  ─┘└─┘                  └─
pid  ────┘                  └─
st   ──────────────────────┘└─
819    apply nat.case_strong_induction_on n, {refl},
id           └──────────────────────────┘ 
src  ─┘└────┘└──────────────────────────┘ └─┘└──┘└──
typ  ───────┘└──────────────────────────┘└─┘└──┘└──
doc  ─┘└────┘                             └─┘└──┘└──
txt  ─┘└────┘                             └─┘└──┘└──
par  ───────┘                             └─┘└──┘└──
pid  ───────┘                             └─────────
st   ─────────────────────────────────────┘└─────┘└─
820    intros n IH, simp,
src  ─┘└─────────┘└┘└──┘└─
typ  ─┘└─────────┘└┘└──┘└─
doc  ─┘└─────────┘└┘└──┘└─
txt  ─┘└─────────┘└┘└──┘└─
par  ─┘└─────────┘└┘└──┘└─
pid  ─────────────────────
st   ────────────┘└────┘└─
821    cases decode α n.unpair.1 with a, {refl},
id           └────┘  └──────┘
src  ─┘└────┘└────┘ └──────┘└───────┘└─┘└──┘└──
typ  ─┘└────┘└────┘└──────┘└───────┘└─┘└──┘└──
doc  ─┘└────┘       └──────┘└───────┘└─┘└──┘└──
txt  ─┘└────┘               └───────┘└─┘└──┘└──
par  ─┘└────┘               └───────┘└─┘└──┘└──
pid  ───────┘               └──────────────────
st   ─────────────────────────────────┘└─────┘└─
822    simp,
src  ─┘└──┘└─
typ  ─┘└──┘└─
doc  ─┘└──┘└─
txt  ─┘└──┘└─
par  ─┘└──┘└─
pid  ────────
st   ─────┘└─
823    suffices : ∀ (o : option (list ℕ)) p (_ : encode o = encode p),
id                       └────┘  └──┘                     
src  ─┘└─────────┘ └────┘└────┘ └──┘ └────────┘               
typ  ─┘└─────────┘ └────┘└────┘ └──┘ └────────┘               
doc  ─┘└─────────┘ └────┘            └────────┘                
txt  ─┘└─────────┘ └────┘            └────────┘                
par  ─┘└─────────┘ └────┘            └────────┘                
pid  ────────────┘ └────┘            └────────┘                
st   ──────────────────────────────────────────────────────────────────
824      encode (option.map (list.cons (encode a)) o) =
src  ───┘                                   └─┘ └┘ 
typ  ───┘                                   └─┘ └┘ 
doc  ───┘                                   └─┘ └┘ 
txt  ───┘                                   └─┘ └┘ 
par  ───┘                                   └─┘ └┘ 
pid  ───┘                                   └─┘ └┘ 
st   ───────────────────────────────────────────────────
825      encode (option.map (list.cons a) p),
id       └────┘  └────────┘  └───────┘ 
src  ───┘└────┘ └────────┘ └───────┘ └┘ └─
typ  ───┘└────┘ └────────┘ └───────┘└┘ └─
doc  ───┘                            └┘ └─
txt  ───┘                            └┘ └─
par  ───┘                            └┘ └─
pid  ───┘                            └┘ └──
st   ──────────────────────────────────────┘└─
826    from this _ _ (IH _ (nat.unpair_le_right n)),
id          └──┘      └┘    └─────────────────┘ 
src  ─┘└───┘    └───┘   └─┘ └─────────────────┘ └┘└─
typ  ──────┘└──┘└───┘ └┘└─┘ └─────────────────┘└───
doc  ─┘└───┘    └───┘   └─┘                     └┘└─
txt  ─┘└───┘    └───┘   └─┘                     └┘└─
par  ──────┘    └───┘   └─┘                     └───
pid  ──────┘    └───┘   └─┘                     └───
st   ─────────────────────────────────────────────┘└─
827    intros o p IH,
src  ─┘└───────────┘└─
typ  ─┘└───────────┘└─
doc  ─┘└───────────┘└─
txt  ─┘└───────────┘└─
par  ─┘└───────────┘└─
pid  ─────────────────
st   ──────────────┘└─
828    cases o; cases p; injection IH with h,
id                               └┘
src  ─┘└────┘ └┘└────┘ └┘└────────┘  └─────┘└─
typ  ─┘└────┘└┘└────┘└┘└────────┘└┘└─────┘└─
doc  ─┘└────┘ └┘└────┘ └┘└────────┘  └─────┘└─
txt  ─┘└────┘ └┘└────┘ └┘└────────┘  └─────┘└─
par  ─┘└────┘ └┘└────┘ └┘└────────┘  └─────┘└─
pid  ───────┘ └──────┘ └──────────┘  └────────
st   ──────────────────────────────────────┘└─
829    exact congr_arg (λ k, (nat.mkpair (encode a) k).succ.succ) h
id           └───────┘        └────────┘  └────┘                 
src  ───────┘└───────┘  └──┘ └────────┘ └────┘ └┘ └───────────┘ 
typ  ───────┘└───────┘  └──┘ └────────┘ └────┘└┘ └───────────┘
doc  ───────┘           └──┘ └────────┘        └┘ └───────────┘ 
txt  ───────┘           └──┘                   └┘ └───────────┘ 
par  ───────┘           └──┘                   └┘ └───────────┘ 
pid  ───────┘           └──┘                   └┘ └───────────┘ 
st   ──────────────────────────────────────────────────────────────┘
830  end⟩
src  ──┘
typ  ──┘
doc  ──┘
txt  ──┘
par  ──┘
pid  ──┘
st   └─┘
831  
832  end primcodable
833  
834  namespace primrec
835  variables {α : Type*} {β : Type*} {γ : Type*} {σ : Type*}
id             
typ            
836  variables [primcodable α] [primcodable β] [primcodable γ] [primcodable σ]
id              └─────────┘     └─────────┘     └─────────┘     └─────────┘
src             └─────────┘     └─────────┘     └─────────┘     └─────────┘
typ             └─────────┘     └─────────┘     └─────────┘     └─────────┘
doc             └─────────┘     └─────────┘     └─────────┘     └─────────┘
837  
838  theorem sum_inl : primrec (@sum.inl α β) :=
id                     └─────┘   └─────┘  
src                    └─────┘   └─────┘
typ                    └─────┘   └─────┘  
doc                    └─────┘
839  encode_iff.1 $ nat_bit0.comp primrec.encode
id   └────────┘    └──────┘└───┘ └────────────┘
src  └────────┘    └──────┘└───┘ └────────────┘
typ  └────────┘    └──────┘└───┘ └────────────┘
840  
841  theorem sum_inr : primrec (@sum.inr α β) :=
id                     └─────┘   └─────┘  
src                    └─────┘   └─────┘
typ                    └─────┘   └─────┘  
doc                    └─────┘
842  encode_iff.1 $ nat_bit1.comp primrec.encode
id   └────────┘    └──────┘└───┘ └────────────┘
src  └────────┘    └──────┘└───┘ └────────────┘
typ  └────────┘    └──────┘└───┘ └────────────┘
843  
844  theorem sum_cases
845    {f : α → β ⊕ γ} {g : α → β → σ} {h : α → γ → σ}
id                                         
src               
typ                                        
846    (hf : primrec f) (hg : primrec₂ g) (hh : primrec₂ h) :
id           └─────┘         └──────┘         └──────┘ 
src          └─────┘          └──────┘          └──────┘
typ          └─────┘         └──────┘         └──────┘ 
doc          └─────┘          └──────┘          └──────┘
847    @primrec _ σ _ _ (λ a, sum.cases_on (f a) (g a) (h a)) :=
id      └─────┘             └──────────┘           
src     └─────┘               └──────────┘
typ     └─────┘             └──────────┘           
doc     └─────┘
848  option_some_iff.1 $
id   └─────────────┘
src  └─────────────┘
typ  └─────────────┘
849  (cond (nat_bodd.comp $ encode_iff.2 hf)
id    └──┘  └──────┘└───┘   └────────┘  └┘
src   └──┘  └──────┘└───┘   └────────┘
typ   └──┘  └──────┘└───┘   └────────┘  └┘
850    (option_map (primrec.decode.comp $ nat_div2.comp $ encode_iff.2 hf) hh)
id      └────────┘  └────────────┘└───┘   └──────┘└───┘   └────────┘  └┘  └┘
src     └────────┘  └────────────┘└───┘   └──────┘└───┘   └────────┘
typ     └────────┘  └────────────┘└───┘   └──────┘└───┘   └────────┘  └┘  └┘
851    (option_map (primrec.decode.comp $ nat_div2.comp $ encode_iff.2 hf) hg)).of_eq $
id      └────────┘  └────────────┘└───┘   └──────┘└───┘   └────────┘  └┘  └┘  └───┘
src     └────────┘  └────────────┘└───┘   └──────┘└───┘   └────────┘          └───┘
typ     └────────┘  └────────────┘└───┘   └──────┘└───┘   └────────┘  └┘  └┘  └───┘
852  λ a, by cases f a with b c;
id                 
src          └────┘  └───────┘
typ         └────┘└───────┘
doc          └────┘  └───────┘
txt          └────┘  └───────┘
par          └────┘  └───────┘
pid                 └───────┘
st          └────────────────────
853    simp [nat.div2_bit, nat.bodd_bit, encodek]; refl
id           └──────────┘  └──────────┘  └─────┘
src    └────┘└──────────┘└┘└──────────┘└┘└─────┘  └────
typ    └────┘└──────────┘└┘└──────────┘└┘└─────┘  └────
doc    └────┘            └┘            └┘         └────
txt    └────┘            └┘            └┘         └────
par    └────┘            └┘            └┘         └────
pid                    └┘            └┘             
st   ───────────────────────────────────────────────────
854  
src  
typ  
doc  
txt  
par  
pid  
st   
855  theorem list_cons : primrec₂ (@list.cons α) :=
id                       └──────┘   └───────┘ 
src                      └──────┘   └───────┘
typ                      └──────┘   └───────┘ 
doc                      └──────┘
856  list_cons' (primcodable.prim _)
id   └────────┘  └──────────────┘
src  └────────┘  └──────────────┘
typ  └────────┘  └──────────────┘
857  
858  theorem list_cases
859    {f : α → list β} {g : α → σ} {h : α → β × list β → σ} :
id             └──┘                       └──┘    
src             └──┘                            └──┘
typ            └──┘                       └──┘    
860    primrec f → primrec g → primrec₂ h →
id     └─────┘    └─────┘    └──────┘ 
src    └─────┘     └─────┘     └──────┘
typ    └─────┘    └─────┘    └──────┘ 
doc    └─────┘     └─────┘     └──────┘
861    @primrec _ σ _ _ (λ a, list.cases_on (f a) (g a) (λ b l, h a (b, l))) :=
id      └─────┘             └───────────┘                   
src     └─────┘               └───────────┘                         
typ     └─────┘             └───────────┘                   
doc     └─────┘
862  list_cases' (primcodable.prim _)
id   └─────────┘  └──────────────┘
src  └─────────┘  └──────────────┘
typ  └─────────┘  └──────────────┘
863  
864  theorem list_foldl
865    {f : α → list β} {g : α → σ} {h : α → σ × β → σ} :
id             └──┘                          
src             └──┘                           
typ            └──┘                          
866    primrec f → primrec g → primrec₂ h →
id     └─────┘    └─────┘    └──────┘ 
src    └─────┘     └─────┘     └──────┘
typ    └─────┘    └─────┘    └──────┘ 
doc    └─────┘     └─────┘     └──────┘
867    primrec (λ a, (f a).foldl (λ s b, h a (s, b)) (g a)) :=
id     └─────┘         └───┘                 
src    └─────┘            └───┘              
typ    └─────┘         └───┘                 
doc    └─────┘
868  list_foldl' (primcodable.prim _)
id   └─────────┘  └──────────────┘
src  └─────────┘  └──────────────┘
typ  └─────────┘  └──────────────┘
869  
870  theorem list_reverse : primrec (@list.reverse α) :=
id                          └─────┘   └──────────┘ 
src                         └─────┘   └──────────┘
typ                         └─────┘   └──────────┘ 
doc                         └─────┘
871  list_reverse' (primcodable.prim _)
id   └───────────┘  └──────────────┘
src  └───────────┘  └──────────────┘
typ  └───────────┘  └──────────────┘
872  
873  theorem list_foldr
874    {f : α → list β} {g : α → σ} {h : α → β × σ → σ}
id             └──┘                          
src             └──┘                           
typ            └──┘                          
875    (hf : primrec f) (hg : primrec g) (hh : primrec₂ h) :
id           └─────┘         └─────┘         └──────┘ 
src          └─────┘          └─────┘          └──────┘
typ          └─────┘         └─────┘         └──────┘ 
doc          └─────┘          └─────┘          └──────┘
876    primrec (λ a, (f a).foldr (λ b s, h a (b, s)) (g a)) :=
id     └─────┘         └───┘                 
src    └─────┘            └───┘              
typ    └─────┘         └───┘                 
doc    └─────┘
877  (list_foldl (list_reverse.comp hf) hg $ to₂ $
id    └────────┘  └──────────┘└───┘ └┘  └┘   └─┘
src   └────────┘  └──────────┘└───┘          └─┘
typ   └────────┘  └──────────┘└───┘ └┘  └┘   └─┘
878    hh.comp fst $ (pair snd fst).comp snd).of_eq $
id     └┘└───┘ └─┘    └──┘ └─┘ └─┘ └──┘  └─┘ └───┘
src      └───┘ └─┘    └──┘ └─┘ └─┘ └──┘  └─┘ └───┘
typ    └┘└───┘ └─┘    └──┘ └─┘ └─┘ └──┘  └─┘ └───┘
879  λ a, by simp [list.foldl_reverse]
id                └────────────────┘
src          └────┘└────────────────┘└─
typ         └────┘└────────────────┘└─
doc          └────┘                  └─
txt          └────┘                  └─
par          └────┘                  └─
pid                                
st          └──────────────────────────
880  
src  
typ  
doc  
txt  
par  
pid  
st   
881  theorem list_head' : primrec (@list.head' α) :=
id                        └─────┘   └────────┘ 
src                       └─────┘   └────────┘
typ                       └─────┘   └────────┘ 
doc                       └─────┘
882  (list_cases primrec.id (const none)
id    └────────┘ └────────┘  └───┘ └──┘
src   └────────┘ └────────┘  └───┘ └──┘
typ   └────────┘ └────────┘  └───┘ └──┘
883    (option_some_iff.2 $ (fst.comp snd)).to₂).of_eq $
id      └─────────────┘     └─┘└───┘ └─┘  └─┘  └───┘
src     └─────────────┘     └─┘└───┘ └─┘  └─┘  └───┘
typ     └─────────────┘     └─┘└───┘ └─┘  └─┘  └───┘
884  λ l, by cases l; refl
id                
src          └────┘   └────
typ         └────┘  └────
doc          └────┘   └────
txt          └────┘   └────
par          └────┘   └────
pid                      
st          └──────────────
885  
src  
typ  
doc  
txt  
par  
pid  
st   
886  theorem list_head [inhabited α] : primrec (@list.head α _) :=
id                      └───────┘     └─────┘   └───────┘ 
src                     └───────┘      └─────┘   └───────┘
typ                     └───────┘     └─────┘   └───────┘ 
doc                                    └─────┘
887  (option_iget.comp list_head').of_eq $
id    └─────────┘└───┘ └────────┘ └───┘
src   └─────────┘└───┘ └────────┘ └───┘
typ   └─────────┘└───┘ └────────┘ └───┘
888  λ l, l.head_eq_head'.symm
id       └────────────┘└───┘
src        └────────────┘└───┘
typ      └────────────┘└───┘
889  
890  theorem list_tail : primrec (@list.tail α) :=
id                       └─────┘   └───────┘ 
src                      └─────┘   └───────┘
typ                      └─────┘   └───────┘ 
doc                      └─────┘
891  (list_cases primrec.id (const []) (snd.comp snd).to₂).of_eq $
id    └────────┘ └────────┘  └───┘ └┘   └─┘└───┘ └─┘ └─┘  └───┘
src   └────────┘ └────────┘  └───┘ └┘   └─┘└───┘ └─┘ └─┘  └───┘
typ   └────────┘ └────────┘  └───┘ └┘   └─┘└───┘ └─┘ └─┘  └───┘
892  λ l, by cases l; refl
id                
src          └────┘   └────
typ         └────┘  └────
doc          └────┘   └────
txt          └────┘   └────
par          └────┘   └────
pid                      
st          └──────────────
893  
src  
typ  
doc  
txt  
par  
pid  
st   
894  theorem list_rec
895    {f : α → list β} {g : α → σ} {h : α → β × list β × σ → σ}
id             └──┘                       └──┘      
src             └──┘                            └──┘   
typ            └──┘                       └──┘      
896    (hf : primrec f) (hg : primrec g) (hh : primrec₂ h) :
id           └─────┘         └─────┘         └──────┘ 
src          └─────┘          └─────┘          └──────┘
typ          └─────┘         └─────┘         └──────┘ 
doc          └─────┘          └─────┘          └──────┘
897    @primrec _ σ _ _ (λ a,
id      └─────┘           
src     └─────┘
typ     └─────┘           
doc     └─────┘
898      list.rec_on (f a) (g a) (λ b l IH, h a (b, l, IH))) :=
id       └─────────┘              └┘        └┘
src      └─────────┘                            
typ      └─────────┘              └┘        └┘
899  let F (a : α) := (f a).foldr
id                     └───┘
src                        └───┘
typ                    └───┘
900    (λ (b : β) (s : list β × σ), (b :: s.1, h a (b, s))) ([], g a) in
id                    └──┘       └┘            └┘   
src                    └──┘          └┘                 └┘
typ                   └──┘       └┘            └┘   
901  have primrec F, from
id        └─────┘ 
src       └─────┘
typ       └─────┘ 
doc       └─────┘
902  list_foldr hf (pair (const []) hg) $ to₂ $
id   └────────┘ └┘  └──┘  └───┘ └┘  └┘    └─┘
src  └────────┘     └──┘  └───┘ └┘        └─┘
typ  └────────┘ └┘  └──┘  └───┘ └┘  └┘    └─┘
903    pair ((list_cons.comp fst (fst.comp snd)).comp snd) hh,
id     └──┘   └───────┘└───┘ └─┘  └─┘└───┘ └─┘  └──┘  └─┘  └┘
src    └──┘   └───────┘└───┘ └─┘  └─┘└───┘ └─┘  └──┘  └─┘
typ    └──┘   └───────┘└───┘ └─┘  └─┘└───┘ └─┘  └──┘  └─┘  └┘
904  (snd.comp this).of_eq $ λ a, begin
id    └─┘└───┘ └──┘ └───┘      
src   └─┘└───┘      └───┘
typ   └─┘└───┘ └──┘ └───┘      
st                                └─────
905    suffices : F a = (f a,
id                   
src    └─────────┘     └─
typ    └─────────┘    └─
doc    └─────────┘      └─
txt    └─────────┘      └─
par    └─────────┘      └─
pid    └───────┘└┘      └─
st   ─────────────────────────
906      list.rec_on (f a) (g a) (λ b l IH, h a (b, l, IH))), {rw this},
id       └─────────┘                                         └──┘
src  ───┘└─────────┘   └┘   └┘  └───────┘   └┘ └┘  └─┘   └─┘
typ  ───┘└─────────┘  └┘  └┘  └───────┘ └┘ └┘  └─┘   └─┘└──┘
doc  ───┘              └┘   └┘  └───────┘    └┘ └┘  └─┘   └─┘
txt  ───┘              └┘   └┘  └───────┘    └┘ └┘  └─┘   └─┘
par  ───┘              └┘   └┘  └───────┘    └┘ └┘  └─┘   └─┘
pid  ───┘              └┘   └┘  └───────┘    └┘ └┘  └─┘     
st   ──────────────────────────────────────────────────────┘└────┘└──┘└┘
907    simp [F], induction f a with b l IH; simp *
id                         
src    └────┘   └────────┘  └──────────┘  └─────┘
typ    └────┘  └────────┘└──────────┘  └─────┘
doc    └────┘   └────────┘  └──────────┘  └─────┘
txt    └────┘   └────────┘  └──────────┘  └─────┘
par    └────┘   └────────┘  └──────────┘  └─────┘
pid                      └─────────┘      
st   ─────────┘└──────────────────────────────────┘
908  end
st   └─┘
909  
910  theorem list_nth : primrec₂ (@list.nth α) :=
id                      └──────┘   └──────┘ 
src                     └──────┘   └──────┘
typ                     └──────┘   └──────┘ 
doc                     └──────┘
911  let F (l : list α) (n : ℕ) :=
id             └──┘        
src             └──┘         
typ            └──┘        
912  l.foldl (λ (s : ℕ ⊕ α) (a : α),
id   └────┘                  
src   └────┘          
typ  └────┘                  
913    sum.cases_on s
id     └──────────┘ 
src    └──────────┘
typ    └──────────┘ 
914      (@nat.cases (ℕ ⊕ α) (sum.inr a) sum.inl) sum.inr)
id         └───────┘       └─────┘   └─────┘  └─────┘
src        └───────┘        └─────┘    └─────┘  └─────┘
typ        └───────┘       └─────┘   └─────┘  └─────┘
915    (sum.inl n) in
id      └─────┘ 
src     └─────┘
typ     └─────┘ 
916  have hF : primrec₂ F, from
id             └──────┘ 
src            └──────┘
typ            └──────┘ 
doc            └──────┘
917  list_foldl fst (sum_inl.comp snd) ((sum_cases fst
id   └────────┘ └─┘  └─────┘└───┘ └─┘    └───────┘ └─┘
src  └────────┘ └─┘  └─────┘└───┘ └─┘    └───────┘ └─┘
typ  └────────┘ └─┘  └─────┘└───┘ └─┘    └───────┘ └─┘
918    (nat_cases snd
id      └───────┘ └─┘
src     └───────┘ └─┘
typ     └───────┘ └─┘
919      (sum_inr.comp $ snd.comp fst)
id        └─────┘└───┘   └─┘└───┘ └─┘
src       └─────┘└───┘   └─┘└───┘ └─┘
typ       └─────┘└───┘   └─┘└───┘ └─┘
920      (sum_inl.comp snd).to₂).to₂
id        └─────┘└───┘ └─┘ └─┘  └─┘
src       └─────┘└───┘ └─┘ └─┘  └─┘
typ       └─────┘└───┘ └─┘ └─┘  └─┘
921    (sum_inr.comp snd).to₂).comp snd).to₂,
id      └─────┘└───┘ └─┘ └─┘  └──┘  └─┘ └─┘
src     └─────┘└───┘ └─┘ └─┘  └──┘  └─┘ └─┘
typ     └─────┘└───┘ └─┘ └─┘  └──┘  └─┘ └─┘
922  have @primrec _ (option α) _ _ (λ p : list α × ℕ,
id         └─────┘    └────┘              └──┘   
src        └─────┘    └────┘               └──┘    
typ        └─────┘    └────┘              └──┘   
doc        └─────┘
923    sum.cases_on (F p.1 p.2) (λ _, none) some), from
id     └──────────┘             └──┘  └──┘
src    └──────────┘                 └──┘  └──┘
typ    └──────────┘             └──┘  └──┘
924  sum_cases hF (const none).to₂ (option_some.comp snd).to₂,
id   └───────┘ └┘  └───┘ └──┘ └─┘   └─────────┘└───┘ └─┘ └─┘
src  └───────┘     └───┘ └──┘ └─┘   └─────────┘└───┘ └─┘ └─┘
typ  └───────┘ └┘  └───┘ └──┘ └─┘   └─────────┘└───┘ └─┘ └─┘
925  this.to₂.of_eq $ λ l n, begin
id   └──┘└──┘└────┘      
src      └──┘└────┘
typ  └──┘└──┘└────┘      
st                           └─────
926    dsimp, symmetry,
src    └───┘  └──────┘
typ    └───┘  └──────┘
doc    └───┘  └──────┘
txt    └───┘  └──────┘
par    └───┘  └──────┘
st   ──────┘└────────┘└─
927    induction l with a l IH generalizing n, {refl},
id               
src    └────────┘ └─────────────────────────┘   └──┘
typ    └────────┘└─────────────────────────┘   └──┘
doc    └────────┘ └─────────────────────────┘   └──┘
txt    └────────┘ └─────────────────────────┘   └──┘
par    └────────┘ └─────────────────────────┘   └──┘
pid              └─────────┘└─────────────┘
st   ───────────────────────────────────────┘└─────┘└┘
928    cases n with n,
id           
src    └────┘ └─────┘
typ    └────┘└─────┘
doc    └────┘ └─────┘
txt    └────┘ └─────┘
par    └────┘ └─────┘
pid          └─────┘
st   ───────────────┘└─
929    { rw [(_ : F (a :: l) 0 = sum.inr a)], {refl},
id                            └─────┘ 
src      └──┘ └──┘      └──┘└─────┘ └┘   └──┘
typ      └──┘ └──┘    └──┘└─────┘└┘   └──┘
doc      └──┘ └──┘      └──┘         └┘   └──┘
txt      └──┘ └──┘      └──┘         └┘   └──┘
par      └──┘ └──┘      └──┘         └┘   └──┘
pid        └┘ └──┘      └──┘         └┘
st   ───┘└────────────────────────────────┘└─────┘└┘
930      clear IH, dsimp [F],
id                        
src      └──────┘  └─────┘ 
typ      └──────┘  └─────┘
doc      └──────┘  └─────┘ 
txt      └──────┘  └─────┘ 
par      └──────┘  └─────┘ 
pid           └─┘        
st   ───────────┘└─────────┘└─
931      induction l with b l IH; simp * },
id                 
src      └────────┘ └──────────┘  └─────┘
typ      └────────┘└──────────┘  └─────┘
doc      └────────┘ └──────────┘  └─────┘
txt      └────────┘ └──────────┘  └─────┘
par      └────────┘ └──────────┘  └─────┘
pid                └─────────┘      
st   ───────────────────────────────────┘└┘
932    { apply IH }
src      └────┘  
typ      └────┘  
doc      └────┘  
txt      └────┘  
par      └────┘  
pid             
st   ────────────┘└─
933  end
st   ──┘
934  
935  theorem list_inth [inhabited α] : primrec₂ (@list.inth α _) :=
id                      └───────┘     └──────┘   └───────┘ 
src                     └───────┘      └──────┘   └───────┘
typ                     └───────┘     └──────┘   └───────┘ 
doc                                    └──────┘   └───────┘
936  option_iget.comp₂ list_nth
id   └─────────┘└────┘ └──────┘
src  └─────────┘└────┘ └──────┘
typ  └─────────┘└────┘ └──────┘
937  
938  theorem list_append : primrec₂ ((++) : list α → list α → list α) :=
id                         └──────┘        └──┘    └──┘    └──┘ 
src                        └──────┘        └──┘     └──┘     └──┘
typ                        └──────┘        └──┘    └──┘    └──┘ 
doc                        └──────┘
939  (list_foldr fst snd $ to₂ $ comp (@list_cons α _) snd).to₂.of_eq $
id    └────────┘ └─┘ └─┘   └─┘   └──┘   └───────┘     └─┘ └─┘ └───┘
src   └────────┘ └─┘ └─┘   └─┘   └──┘   └───────┘      └─┘ └─┘ └───┘
typ   └────────┘ └─┘ └─┘   └─┘   └──┘   └───────┘     └─┘ └─┘ └───┘
940  λ l₁ l₂, by induction l₁; simp *
id     └┘ └┘               └┘
src              └────────┘    └──────
typ    └┘ └┘     └────────┘└┘  └──────
doc              └────────┘    └──────
txt              └────────┘    └──────
par              └────────┘    └──────
pid                               
st              └─────────────────────
941  
src  
typ  
doc  
txt  
par  
pid  
st   
942  theorem list_concat : primrec₂ (λ l (a:α), l ++ [a]) :=
id                         └──────┘            └┘ 
src                        └──────┘               └┘  
typ                        └──────┘            └┘ 
doc                        └──────┘
943  list_append.comp fst (list_cons.comp snd (const []))
id   └─────────┘└───┘ └─┘  └───────┘└───┘ └─┘  └───┘ └┘
src  └─────────┘└───┘ └─┘  └───────┘└───┘ └─┘  └───┘ └┘
typ  └─────────┘└───┘ └─┘  └───────┘└───┘ └─┘  └───┘ └┘
944  
945  theorem list_map
946    {f : α → list β} {g : α → β → σ}
id             └──┘              
src             └──┘
typ            └──┘              
947    (hf : primrec f) (hg : primrec₂ g) :
id           └─────┘         └──────┘ 
src          └─────┘          └──────┘
typ          └─────┘         └──────┘ 
doc          └─────┘          └──────┘
948    primrec (λ a, (f a).map (g a)) :=
id     └─────┘         └─┘    
src    └─────┘            └─┘
typ    └─────┘         └─┘    
doc    └─────┘
949  (list_foldr hf (const []) $ to₂ $ list_cons.comp
id    └────────┘ └┘  └───┘ └┘    └─┘   └───────┘└───┘
src   └────────┘     └───┘ └┘    └─┘   └───────┘└───┘
typ   └────────┘ └┘  └───┘ └┘    └─┘   └───────┘└───┘
950    (hg.comp fst (fst.comp snd)) (snd.comp snd)).of_eq $
id      └┘└───┘ └─┘  └─┘└───┘ └─┘    └─┘└───┘ └─┘  └───┘
src       └───┘ └─┘  └─┘└───┘ └─┘    └─┘└───┘ └─┘  └───┘
typ     └┘└───┘ └─┘  └─┘└───┘ └─┘    └─┘└───┘ └─┘  └───┘
951  λ a, by induction f a; simp *
id                     
src          └────────┘    └──────
typ         └────────┘  └──────
doc          └────────┘    └──────
txt          └────────┘    └──────
par          └────────┘    └──────
pid                           
st          └──────────────────────
952  
src  
typ  
doc  
txt  
par  
pid  
st   
953  theorem list_range : primrec list.range :=
id                        └─────┘ └────────┘
src                       └─────┘ └────────┘
typ                       └─────┘ └────────┘
doc                       └─────┘
954  (nat_elim' primrec.id (const [])
id    └───────┘ └────────┘  └───┘ └┘
src   └───────┘ └────────┘  └───┘ └┘
typ   └───────┘ └────────┘  └───┘ └┘
955    ((list_concat.comp snd fst).comp snd).to₂).of_eq $
id       └─────────┘└───┘ └─┘ └─┘ └──┘  └─┘ └─┘  └───┘
src      └─────────┘└───┘ └─┘ └─┘ └──┘  └─┘ └─┘  └───┘
typ      └─────────┘└───┘ └─┘ └─┘ └──┘  └─┘ └─┘  └───┘
956  λ n, by simp; induction n; simp [*, list.range_concat]; refl
id                                     └───────────────┘
src          └──┘  └────────┘   └───────┘└───────────────┘  └────
typ         └──┘  └────────┘  └───────┘└───────────────┘  └────
doc          └──┘  └────────┘   └───────┘                   └────
txt          └──┘  └────────┘   └───────┘                   └────
par          └──┘  └────────┘   └───────┘                   └────
pid                                └──┘                       
st          └─────────────────────────────────────────────────────
957  
src  
typ  
doc  
txt  
par  
pid  
st   
958  theorem list_join : primrec (@list.join α) :=
id                       └─────┘   └───────┘ 
src                      └─────┘   └───────┘
typ                      └─────┘   └───────┘ 
doc                      └─────┘
959  (list_foldr primrec.id (const []) $ to₂ $
id    └────────┘ └────────┘  └───┘ └┘    └─┘
src   └────────┘ └────────┘  └───┘ └┘    └─┘
typ   └────────┘ └────────┘  └───┘ └┘    └─┘
960    comp (@list_append α _) snd).of_eq $
id     └──┘   └─────────┘     └─┘ └───┘
src    └──┘   └─────────┘      └─┘ └───┘
typ    └──┘   └─────────┘     └─┘ └───┘
961  λ l, by dsimp; induction l; simp *
id                           
src          └───┘  └────────┘   └──────
typ         └───┘  └────────┘  └──────
doc          └───┘  └────────┘   └──────
txt          └───┘  └────────┘   └──────
par          └───┘  └────────┘   └──────
pid                                 
st          └───────────────────────────
962  
src  
typ  
doc  
txt  
par  
pid  
st   
963  theorem list_length : primrec (@list.length α) :=
id                         └─────┘   └─────────┘ 
src                        └─────┘   └─────────┘
typ                        └─────┘   └─────────┘ 
doc                        └─────┘
964  (list_foldr (@primrec.id (list α) _) (const 0) $ to₂ $
id    └────────┘   └────────┘  └──┘       └───┘      └─┘
src   └────────┘   └────────┘  └──┘        └───┘      └─┘
typ   └────────┘   └────────┘  └──┘       └───┘      └─┘
965    (succ.comp $ snd.comp snd).to₂).of_eq $
id      └──┘└───┘   └─┘└───┘ └─┘ └─┘  └───┘
src     └──┘└───┘   └─┘└───┘ └─┘ └─┘  └───┘
typ     └──┘└───┘   └─┘└───┘ └─┘ └─┘  └───┘
966  λ l, by dsimp; induction l; simp [*, -add_comm]
id                           
src          └───┘  └────────┘   └───────────────────
typ         └───┘  └────────┘  └───────────────────
doc          └───┘  └────────┘   └───────────────────
txt          └───┘  └────────┘   └───────────────────
par          └───┘  └────────┘   └───────────────────
pid                                 └────────────┘
st          └────────────────────────────────────────
967  
src  
typ  
doc  
txt  
par  
pid  
st   
968  theorem list_find_index {f : α → list β} {p : α → β → Prop}
id                                   └──┘           
src                                   └──┘
typ                                  └──┘           
969    [∀ a b, decidable (p a b)]
id           └───────┘    
src            └───────┘
typ          └───────┘    
970    (hf : primrec f) (hp : primrec_rel p) :
id           └─────┘         └─────────┘ 
src          └─────┘          └─────────┘
typ          └─────┘         └─────────┘ 
doc          └─────┘          └─────────┘
971    primrec (λ a, (f a).find_index (p a)) :=
id     └─────┘         └────────┘    
src    └─────┘            └────────┘
typ    └─────┘         └────────┘    
doc    └─────┘
972  (list_foldr hf (const 0) $ to₂ $
id    └────────┘ └┘  └───┘      └─┘
src   └────────┘     └───┘      └─┘
typ   └────────┘ └┘  └───┘      └─┘
973    ite (hp.comp fst $ fst.comp snd) (const 0)
id     └─┘  └┘└───┘ └─┘   └─┘└───┘ └─┘   └───┘
src    └─┘    └───┘ └─┘   └─┘└───┘ └─┘   └───┘
typ    └─┘  └┘└───┘ └─┘   └─┘└───┘ └─┘   └───┘
974      (succ.comp $ snd.comp snd)).of_eq $
id        └──┘└───┘   └─┘└───┘ └─┘  └───┘
src       └──┘└───┘   └─┘└───┘ └─┘  └───┘
typ       └──┘└───┘   └─┘└───┘ └─┘  └───┘
975  λ a, eq.symm $ by dsimp; induction f a with b l;
id       └─────┘                        
src       └─────┘      └───┘  └────────┘  └───────┘
typ      └─────┘      └───┘  └────────┘└───────┘
doc                    └───┘  └────────┘  └───────┘
txt                    └───┘  └────────┘  └───────┘
par                    └───┘  └────────┘  └───────┘
pid                                      └──────┘
st                    └───────────────────────────────
976    [refl, { simp [*, list.find_index], congr }]
id                      └─────────────┘
src    └──┘    └───────┘└─────────────┘  └────┘
typ    └──┘    └───────┘└─────────────┘  └────┘
doc     └──┘    └───────┘               
txt     └──┘    └───────┘                 └────┘
par     └──┘    └───────┘                 └────┘
pid                 └──┘                      
st   ────────┘└─────────────────────────┘└──────┘└┘
977  
978  theorem list_index_of [decidable_eq α] : primrec₂ (@list.index_of α _) :=
id                          └──────────┘     └──────┘   └───────────┘ 
src                         └──────────┘      └──────┘   └───────────┘
typ                         └──────────┘     └──────┘   └───────────┘ 
doc                                           └──────┘
979  to₂ $ list_find_index snd $ primrec.eq.comp₂ (fst.comp fst).to₂ snd.to₂
id   └─┘   └─────────────┘ └─┘   └────────┘└────┘  └─┘└───┘ └─┘ └─┘  └─┘└──┘
src  └─┘   └─────────────┘ └─┘   └────────┘└────┘  └─┘└───┘ └─┘ └─┘  └─┘└──┘
typ  └─┘   └─────────────┘ └─┘   └────────┘└────┘  └─┘└───┘ └─┘ └─┘  └─┘└──┘
980  
981  theorem nat_strong_rec
982    (f : α → ℕ → σ) {g : α → list σ → option σ} (hg : primrec₂ g)
id                          └──┘    └────┘         └──────┘ 
src                            └──┘     └────┘          └──────┘
typ                         └──┘    └────┘         └──────┘ 
doc                                                      └──────┘
983    (H : ∀ a n, g a ((list.range n).map (f a)) = some (f a n)) : primrec₂ f :=
id                   └────────┘  └─┘        └──┘         └──────┘ 
src                      └────────┘   └─┘          └──┘            └──────┘
typ                  └────────┘  └─┘        └──┘         └──────┘ 
doc                                                                 └──────┘
984  suffices primrec₂ (λ a n, (list.range n).map (f a)), from
id            └──────┘        └────────┘  └─┘    
src           └──────┘          └────────┘   └─┘
typ           └──────┘        └────────┘  └─┘    
doc           └──────┘
985    primrec₂.option_some_iff.1 $
id     └──────────────────────┘
src    └──────────────────────┘
typ    └──────────────────────┘
986    (list_nth.comp (this.comp fst (succ.comp snd)) snd).to₂.of_eq $
id      └──────┘└───┘  └──┘└───┘ └─┘  └──┘└───┘ └─┘   └─┘ └─┘ └───┘
src     └──────┘└───┘      └───┘ └─┘  └──┘└───┘ └─┘   └─┘ └─┘ └───┘
typ     └──────┘└───┘  └──┘└───┘ └─┘  └──┘└───┘ └─┘   └─┘ └─┘ └───┘
987    λ a n, by simp [list.nth_range (nat.lt_succ_self n)]; refl,
id                   └────────────┘  └──────────────┘ 
src              └────┘└────────────┘ └──────────────┘ └┘  └──┘
typ            └────┘└────────────┘ └──────────────┘└┘  └──┘
doc              └────┘                                └┘  └──┘
txt              └────┘                                └┘  └──┘
par              └────┘                                └┘  └──┘
pid                                                  └┘
st              └───────────────────────────────────────────────┘
988  primrec₂.option_some_iff.1 $
id   └──────────────────────┘
src  └──────────────────────┘
typ  └──────────────────────┘
989  (nat_elim (const (some [])) (to₂ $
id    └──────┘  └───┘  └──┘ └┘    └─┘
src   └──────┘  └───┘  └──┘ └┘    └─┘
typ   └──────┘  └───┘  └──┘ └┘    └─┘
990    option_bind (snd.comp snd) $ to₂ $
id     └─────────┘  └─┘└───┘ └─┘    └─┘
src    └─────────┘  └─┘└───┘ └─┘    └─┘
typ    └─────────┘  └─┘└───┘ └─┘    └─┘
991    option_map
id     └────────┘
src    └────────┘
typ    └────────┘
992      (hg.comp (fst.comp fst) snd)
id        └┘└───┘  └─┘└───┘ └─┘  └─┘
src         └───┘  └─┘└───┘ └─┘  └─┘
typ       └┘└───┘  └─┘└───┘ └─┘  └─┘
993      (to₂ $ list_concat.comp (snd.comp fst) snd))).of_eq $
id        └─┘   └─────────┘└───┘  └─┘└───┘ └─┘  └─┘   └───┘
src       └─┘   └─────────┘└───┘  └─┘└───┘ └─┘  └─┘   └───┘
typ       └─┘   └─────────┘└───┘  └─┘└───┘ └─┘  └─┘   └───┘
994  λ a n, begin
id      
typ     
st          └─────
995    simp, induction n with n IH, {refl},
id                     
src    └──┘  └────────┘ └────────┘   └──┘
typ    └──┘  └────────┘└────────┘   └──┘
doc    └──┘  └────────┘ └────────┘   └──┘
txt    └──┘  └────────┘ └────────┘   └──┘
par    └──┘  └────────┘ └────────┘   └──┘
pid                    └───────┘
st   ─────┘└─────────────────────┘└─────┘└┘
996    simp [IH, H, list.range_concat]
id           └┘    └───────────────┘
src    └────┘  └┘ └┘└───────────────┘└┘
typ    └────┘└┘└┘└┘└───────────────┘└┘
doc    └────┘  └┘ └┘                 └┘
txt    └────┘  └┘ └┘                 └┘
par    └────┘  └┘ └┘                 └┘
pid          └┘ └┘                 
st   ─────────────────────────────────┘
997  end
st   └─┘
998  
999  end primrec
1000  
1001  namespace primcodable
1002  variables {α : Type*} {β : Type*}
1003  variables [primcodable α] [primcodable β]
id              └─────────┘     └─────────┘
src             └─────────┘     └─────────┘
typ             └─────────┘     └─────────┘
doc             └─────────┘     └─────────┘
1004  open primrec
1005  
1006  def subtype {p : α → Prop} [decidable_pred p]
id                              └────────────┘ 
src                              └────────────┘
typ                             └────────────┘ 
1007    (hp : primrec_pred p) : primcodable (subtype p) :=
id           └──────────┘     └─────────┘  └─────┘ 
src          └──────────┘      └─────────┘  └─────┘
typ          └──────────┘     └─────────┘  └─────┘ 
doc          └──────────┘      └─────────┘
1008  ⟨have primrec (λ n, (decode α n).bind (λ a, option.guard p a)),
id         └─────┘       └────┘   └──┘       └──────────┘  
src        └─────┘        └────┘     └──┘        └──────────┘
typ        └─────┘       └────┘   └──┘       └──────────┘  
doc        └─────┘                               └──────────┘
1009   from option_bind primrec.decode (option_guard (hp.comp snd) snd),
id         └─────────┘ └────────────┘  └──────────┘  └┘└───┘ └─┘  └─┘
src        └─────────┘ └────────────┘  └──────────┘    └───┘ └─┘  └─┘
typ        └─────────┘ └────────────┘  └──────────┘  └┘└───┘ └─┘  └─┘
1010   nat_iff.1 $ (encode_iff.2 this).of_eq $ λ n,
id    └─────┘     └────────┘  └──┘ └───┘      
src   └─────┘     └────────┘       └───┘      
typ   └─────┘     └────────┘  └──┘ └───┘      
1011   show _ = encode ((decode α n).bind (λ a, _)), begin
id            └────┘   └────┘   └──┘     
src           └────┘   └────┘     └──┘
typ           └────┘   └────┘   └──┘     
st                                                  └─────
1012     cases decode α n with a, {refl},
id            └────┘  
src     └────┘└────┘  └─────┘   └──┘
typ     └────┘└────┘└─────┘   └──┘
doc     └────┘        └─────┘   └──┘
txt     └────┘        └─────┘   └──┘
par     └────┘        └─────┘   └──┘
pid                  └─────┘
st   ─────────────────────────┘└─────┘└┘
1013     dsimp [option.guard],
id             └──────────┘
src     └─────┘└──────────┘
typ     └─────┘└──────────┘
doc     └─────┘└──────────┘
txt     └─────┘            
par     └─────┘            
pid                      
st   ──────────────────────┘└─
1014     by_cases h : p a; simp [h]; refl
id                            
src     └───────┘ └─┘    └────┘   └────
typ     └───────┘ └─┘  └────┘  └────
doc     └───────┘ └─┘    └────┘   └────
txt     └───────┘ └─┘    └────┘   └────
par     └───────┘ └─┘    └────┘   └────
pid              └─┘               
st   ────────────────────────────────────
1015   end⟩
src  
typ  
doc  
txt  
par  
pid  
st   └─┘
1016  
1017  instance fin {n} : primcodable (fin n) :=
id                      └─────────┘  └─┘ 
src                     └─────────┘  └─┘
typ                     └─────────┘  └─┘ 
doc                     └─────────┘
1018  @of_equiv _ _
id    └──────┘
src   └──────┘
typ   └──────┘
1019    (subtype $ nat_lt.comp primrec.id (const n))
id      └─────┘   └────┘└───┘ └────────┘  └───┘ 
src     └─────┘   └────┘└───┘ └────────┘  └───┘
typ     └─────┘   └────┘└───┘ └────────┘  └───┘ 
1020    (equiv.fin_equiv_subtype _)
id      └─────────────────────┘
src     └─────────────────────┘
typ     └─────────────────────┘
1021  
1022  instance vector {n} : primcodable (vector α n) :=
id                         └─────────┘  └────┘  
src                        └─────────┘  └────┘
typ                        └─────────┘  └────┘  
doc                        └─────────┘
1023  subtype ((@primrec.eq _ _ nat.decidable_eq).comp list_length (const _))
id   └─────┘    └────────┘     └──────────────┘ └──┘  └─────────┘  └───┘
src  └─────┘    └────────┘     └──────────────┘ └──┘  └─────────┘  └───┘
typ  └─────┘    └────────┘     └──────────────┘ └──┘  └─────────┘  └───┘
1024  
1025  instance fin_arrow {n} : primcodable (fin n → α) :=
id                            └─────────┘  └─┘    
src                           └─────────┘  └─┘
typ                           └─────────┘  └─┘    
doc                           └─────────┘
1026  of_equiv _ (equiv.vector_equiv_fin _ _).symm
id   └──────┘    └────────────────────┘     └──┘
src  └──────┘    └────────────────────┘     └──┘
typ  └──────┘    └────────────────────┘     └──┘
1027  
1028  instance array {n} : primcodable (array n α) :=
id                        └─────────┘  └───┘  
src                       └─────────┘  └───┘
typ                       └─────────┘  └───┘  
doc                       └─────────┘
1029  of_equiv _ (equiv.array_equiv_fin _ _)
id   └──────┘    └───────────────────┘
src  └──────┘    └───────────────────┘
typ  └──────┘    └───────────────────┘
1030  
1031  end primcodable
1032  
1033  namespace primrec
1034  variables {α : Type*} {β : Type*} {γ : Type*} {σ : Type*}
id             
typ            
1035  variables [primcodable α] [primcodable β] [primcodable γ] [primcodable σ]
id              └─────────┘     └─────────┘     └─────────┘     └─────────┘
src             └─────────┘     └─────────┘     └─────────┘     └─────────┘
typ             └─────────┘     └─────────┘     └─────────┘     └─────────┘
doc             └─────────┘     └─────────┘     └─────────┘     └─────────┘
1036  
1037  theorem subtype_val {p : α → Prop} [decidable_pred p]
id                                      └────────────┘ 
src                                      └────────────┘
typ                                     └────────────┘ 
1038    {hp : primrec_pred p} :
id           └──────────┘ 
src          └──────────┘
typ          └──────────┘ 
doc          └──────────┘
1039    by haveI := primcodable.subtype hp; exact
id                 └─────────────────┘ └┘
src       └───────┘└─────────────────┘    └─────
typ       └───────┘└─────────────────┘└┘  └─────
doc       └───────┘                       └─────
txt       └───────┘                       └─────
par       └───────┘                       └─────
pid            └─┘                            
st       └───────────────────────────────────────
1040    primrec (@subtype.val α p) :=
id     └─────┘   └─────────┘  
src  ─┘└─────┘  └─────────┘  └┘
typ  ─┘└─────┘  └─────────┘└┘
doc  ─┘└─────┘               └┘
txt  ─┘                      └┘
par  ─┘                      └┘
pid  ─┘                      
st   ────────────────────────────┘
1041  begin
st   └─────
1042    letI := primcodable.subtype hp,
id             └─────────────────┘ └┘
src    └──────┘└─────────────────┘
typ    └──────┘└─────────────────┘└┘
doc    └──────┘                   
txt    └──────┘                   
par    └──────┘                   
pid        └─┘                   
st   ───────────────────────────────┘└─
1043    refine (primcodable.prim (subtype p)).of_eq (λ n, _),
id             └──────────────┘  └─────┘ 
src    └─────┘ └──────────────┘ └─────┘ └───────┘  └────┘
typ    └─────┘ └──────────────┘ └─────┘└───────┘  └────┘
doc    └─────┘                          └───────┘  └────┘
txt    └─────┘                          └───────┘  └────┘
par    └─────┘                          └───────┘  └────┘
pid                                    └───────┘  └────┘
st   ─────────────────────────────────────────────────────┘└─
1044    rcases decode (subtype p) n with _|⟨a,h⟩; refl
id            └────┘  └─────┘   
src    └─────┘└────┘ └─────┘ └┘ └───────────┘  └───┘
typ    └─────┘└────┘ └─────┘└┘└───────────┘  └───┘
doc    └─────┘               └┘ └───────────┘  └───┘
txt    └─────┘               └┘ └───────────┘  └───┘
par    └─────┘               └┘ └───────────┘  └───┘
pid                         └┘ └───────────┘      
st   ────────────────────────────────────────────────┘
1045  end
st   └─┘
1046  
1047  theorem subtype_val_iff {p : β → Prop} [decidable_pred p]
id                                          └────────────┘ 
src                                          └────────────┘
typ                                         └────────────┘ 
1048    {hp : primrec_pred p} {f : α → subtype p} :
id           └──────────┘           └─────┘ 
src          └──────────┘             └─────┘
typ          └──────────┘           └─────┘ 
doc          └──────────┘
1049    by haveI := primcodable.subtype hp; exact
id                 └─────────────────┘ └┘
src       └───────┘└─────────────────┘    └─────
typ       └───────┘└─────────────────┘└┘  └─────
doc       └───────┘                       └─────
txt       └───────┘                       └─────
par       └───────┘                       └─────
pid            └─┘                            
st       └───────────────────────────────────────
1050    primrec (λ a, (f a).1) ↔ primrec f :=
id                             └─────┘ 
src  ─┘         └──┘   └───┘└─────┘ 
typ  ─┘         └──┘   └───┘└─────┘
doc  ─┘         └──┘   └───┘ └─────┘ 
txt  ─┘         └──┘   └───┘         
par  ─┘         └──┘   └───┘         
pid  ─┘         └──┘   └───┘         
st   ────────────────────────────────────┘
1051  begin
st   └─────
1052    letI := primcodable.subtype hp,
id             └─────────────────┘ └┘
src    └──────┘└─────────────────┘
typ    └──────┘└─────────────────┘└┘
doc    └──────┘                   
txt    └──────┘                   
par    └──────┘                   
pid        └─┘                   
st   ───────────────────────────────┘└─
1053    refine ⟨λ h, _, λ hf, subtype_val.comp hf⟩,
id                           └──────────────┘
src    └─────┘  └─────┘ └───┘└──────────────┘  
typ    └─────┘  └─────┘ └───┘└──────────────┘  
doc    └─────┘  └─────┘ └───┘                  
txt    └─────┘  └─────┘ └───┘                  
par    └─────┘  └─────┘ └───┘                  
pid            └─────┘ └───┘                  
st   ───────────────────────────────────────────┘└─
1054    refine nat.primrec.of_eq h (λ n, _),
id            └───────────────┘ 
src    └─────┘└───────────────┘   └────┘
typ    └─────┘└───────────────┘  └────┘
doc    └─────┘                    └────┘
txt    └─────┘                    └────┘
par    └─────┘                    └────┘
pid                              └────┘
st   ────────────────────────────────────┘└─
1055    cases decode α n with a, {refl},
id           └────┘  
src    └────┘└────┘  └─────┘   └──┘
typ    └────┘└────┘└─────┘   └──┘
doc    └────┘        └─────┘   └──┘
txt    └────┘        └─────┘   └──┘
par    └────┘        └─────┘   └──┘
pid                 └─────┘
st   ────────────────────────┘└─────┘└┘
1056    simp, cases f a; refl
id                  
src    └──┘  └────┘    └───┘
typ    └──┘  └────┘  └───┘
doc    └──┘  └────┘    └───┘
txt    └──┘  └────┘    └───┘
par    └──┘  └────┘    └───┘
pid                       
st   ─────┘└────────────────┘
1057  end
st   └─┘
1058  
1059  theorem fin_val_iff {n} {f : α → fin n} :
id                                   └─┘ 
src                                   └─┘
typ                                  └─┘ 
1060    primrec (λ a, (f a).1) ↔ primrec f :=
id     └─────┘             └─────┘ 
src    └─────┘                └─────┘
typ    └─────┘             └─────┘ 
doc    └─────┘                  └─────┘
1061  begin
st   └─────
1062    let : primcodable {a//id a<n}, swap,
id           └─────────┘    └┘  
src    └────┘└─────────┘└─┘└┘    └──┘
typ    └────┘└─────────┘└─┘└┘   └──┘
doc    └────┘└─────────┘ └─┘       └──┘
txt    └────┘            └─┘       └──┘
par    └────┘            └─┘       └──┘
pid    └──┘└┘            └─┘     
st   ──────────────────────────────┘└────┘└─
1063    exactI (iff.trans (by refl) subtype_val_iff).trans (of_equiv_iff _)
id             └───────┘           └─────────────┘         └──────────┘
src    └─────┘ └───────┘   └──┘└┘└─────────────┘└──────┘ └──────────┘└──┘
typ    └─────┘ └───────┘   └──┘└┘└─────────────┘└──────┘ └──────────┘└──┘
doc    └─────┘             └──┘└┘               └──────┘             └──┘
txt    └─────┘             └──┘└┘               └──────┘             └──┘
par    └─────┘             └──┘└┘               └──────┘             └──┘
pid                       └─────┘               └──────┘             └─┘
st   ──────────────────────┘└───┘└────────────────────────────────────────┘
1064  end
st   └─┘
1065  
1066  theorem fin_val {n} : primrec (@fin.val n) := fin_val_iff.2 primrec.id
id                         └─────┘   └─────┘      └─────────┘  └────────┘
src                        └─────┘   └─────┘       └─────────┘  └────────┘
typ                        └─────┘   └─────┘      └─────────┘  └────────┘
doc                        └─────┘
1067  
1068  theorem fin_succ {n} : primrec (@fin.succ n) :=
id                          └─────┘   └──────┘ 
src                         └─────┘   └──────┘
typ                         └─────┘   └──────┘ 
doc                         └─────┘
1069  fin_val_iff.1 $ by simp [succ.comp fin_val]
id   └─────────┘             └───────┘ └─────┘
src  └─────────┘       └────┘└───────┘└─────┘└─
typ  └─────────┘       └────┘└───────┘└─────┘└─
doc                     └────┘                └─
txt                     └────┘                └─
par                     └────┘                └─
pid                                         
st                     └─────────────────────────
1070  
src  
typ  
doc  
txt  
par  
pid  
st   
1071  theorem vector_to_list {n} : primrec (@vector.to_list α n) := subtype_val
id                                └─────┘   └────────────┘       └─────────┘
src                               └─────┘   └────────────┘         └─────────┘
typ                               └─────┘   └────────────┘       └─────────┘
doc                               └─────┘
1072  
1073  theorem vector_to_list_iff {n} {f : α → vector β n} :
id                                          └────┘  
src                                          └────┘
typ                                         └────┘  
1074    primrec (λ a, (f a).to_list) ↔ primrec f := subtype_val_iff
id     └─────┘         └─────┘    └─────┘     └─────────────┘
src    └─────┘            └─────┘    └─────┘      └─────────────┘
typ    └─────┘         └─────┘    └─────┘     └─────────────┘
doc    └─────┘                        └─────┘
1075  
1076  theorem vector_cons {n} : primrec₂ (@vector.cons α n) :=
id                             └──────┘   └─────────┘  
src                            └──────┘   └─────────┘
typ                            └──────┘   └─────────┘  
doc                            └──────┘
1077  vector_to_list_iff.1 $ by simp; exact
id   └────────────────┘
src  └────────────────┘       └──┘  └────┘
typ  └────────────────┘       └──┘  └────┘
doc                            └──┘  └────┘
txt                            └──┘  └────┘
par                            └──┘  └────┘
pid                                       
st                            └────────────
1078  list_cons.comp fst (vector_to_list_iff.2 snd)
id   └────────────┘ └─┘  └────────────────┘   └─┘
src  └────────────┘└─┘ └────────────────┘└─┘└─┘└─
typ  └────────────┘└─┘ └────────────────┘└─┘└─┘└─
doc                                      └─┘   └─
txt                                      └─┘   └─
par                                      └─┘   └─
pid                                      └─┘   
st   ──────────────────────────────────────────────
1079  
src  
typ  
doc  
txt  
par  
pid  
st   
1080  theorem vector_length {n} : primrec (@vector.length α n) := const _
id                               └─────┘   └───────────┘       └───┘
src                              └─────┘   └───────────┘         └───┘
typ                              └─────┘   └───────────┘       └───┘
doc                              └─────┘
1081  
1082  theorem vector_head {n} : primrec (@vector.head α n) :=
id                             └─────┘   └─────────┘  
src                            └─────┘   └─────────┘
typ                            └─────┘   └─────────┘  
doc                            └─────┘
1083  option_some_iff.1 $
id   └─────────────┘
src  └─────────────┘
typ  └─────────────┘
1084  (list_head'.comp vector_to_list).of_eq $ λ ⟨a::l, h⟩, rfl
id    └────────┘└───┘ └────────────┘ └───┘       └┘       └─┘
src   └────────┘└───┘ └────────────┘ └───┘        └┘       └─┘
typ   └────────┘└───┘ └────────────┘ └───┘       └┘       └─┘
1085  
1086  theorem vector_tail {n} : primrec (@vector.tail α n) :=
id                             └─────┘   └─────────┘  
src                            └─────┘   └─────────┘
typ                            └─────┘   └─────────┘  
doc                            └─────┘
1087  vector_to_list_iff.1 $ (list_tail.comp vector_to_list).of_eq $
id   └────────────────┘     └───────┘└───┘ └────────────┘ └───┘
src  └────────────────┘     └───────┘└───┘ └────────────┘ └───┘
typ  └────────────────┘     └───────┘└───┘ └────────────┘ └───┘
1088  λ ⟨l, h⟩, by cases l; refl
id                     
src               └────┘   └────
typ              └────┘  └────
doc               └────┘   └────
txt               └────┘   └────
par               └────┘   └────
pid                           
st               └──────────────
1089  
src  
typ  
doc  
txt  
par  
pid  
st   
1090  theorem vector_nth {n} : primrec₂ (@vector.nth α n) :=
id                            └──────┘   └────────┘  
src                           └──────┘   └────────┘
typ                           └──────┘   └────────┘  
doc                           └──────┘
1091  option_some_iff.1 $
id   └─────────────┘
src  └─────────────┘
typ  └─────────────┘
1092  (list_nth.comp (vector_to_list.comp fst) (fin_val.comp snd)).of_eq $
id    └──────┘└───┘  └────────────┘└───┘ └─┘   └─────┘└───┘ └─┘  └───┘
src   └──────┘└───┘  └────────────┘└───┘ └─┘   └─────┘└───┘ └─┘  └───┘
typ   └──────┘└───┘  └────────────┘└───┘ └─┘   └─────┘└───┘ └─┘  └───┘
1093  λ a, by simp [vector.nth_eq_nth_le]; rw [← list.nth_le_nth]
id                └──────────────────┘         └─────────────┘
src          └────┘└──────────────────┘  └────┘└─────────────┘└─
typ         └────┘└──────────────────┘  └────┘└─────────────┘└─
doc          └────┘                      └────┘               └─
txt          └────┘                      └────┘               └─
par          └────┘                      └────┘               └─
pid                                      └──┘               
st          └────────────────────────────────┘└───────────────┘
1094  
src  
typ  
doc  
txt  
par  
pid  
st   
1095  theorem list_of_fn : ∀ {n} {f : fin n → α → σ},
id                                 └─┘      
src                                  └─┘
typ                                └─┘      
1096    (∀ i, primrec (f i)) → primrec (λ a, list.of_fn (λ i, f i a))
id          └─────┘        └─────┘      └────────┘        
src          └─────┘          └─────┘       └────────┘
typ         └─────┘        └─────┘      └────────┘        
doc          └─────┘          └─────┘
1097  | 0     f hf := const []
id                   └───┘ └┘
src                  └───┘ └┘
typ                  └───┘ └┘
1098  | (n+1) f hf := by simp [list.of_fn_succ]; exact
id                           └─────────────┘
src                    └────┘└─────────────┘  └─────
typ                    └────┘└─────────────┘  └─────
doc                     └────┘                 └─────
txt                     └────┘                 └─────
par                     └────┘                 └─────
pid                                               
st                     └──────────────────────────────
1099    list_cons.comp (hf 0) (list_of_fn (λ i, hf i.succ))
id     └────────────┘         └────────┘       └┘  └───┘
src  ─┘└────────────┘   └──┘             └──┘   └───┘└──
typ  ─┘└────────────┘   └──┘ └────────┘  └──┘└┘ └───┘└──
doc  ─┘                 └──┘             └──┘        └──
txt  ─┘                 └──┘             └──┘        └──
par  ─┘                 └──┘             └──┘        └──
pid  ─┘                 └──┘             └──┘        └┘
st   ──────────────────────────────────────────────────────
1100  
src  
typ  
doc  
txt  
par  
pid  
st   
1101  theorem vector_of_fn {n} {f : fin n → α → σ}
id                                 └─┘       
src                                └─┘
typ                                └─┘       
1102    (hf : ∀ i, primrec (f i)) : primrec (λ a, vector.of_fn (λ i, f i a)) :=
id               └─────┘        └─────┘      └──────────┘        
src               └─────┘          └─────┘       └──────────┘
typ              └─────┘        └─────┘      └──────────┘        
doc               └─────┘          └─────┘
1103  vector_to_list_iff.1 $ by simp [list_of_fn hf]
id   └────────────────┘             └────────┘ └┘
src  └────────────────┘       └────┘└────────┘  └─
typ  └────────────────┘       └────┘└────────┘└┘└─
doc                            └────┘            └─
txt                            └────┘            └─
par                            └────┘            └─
pid                                            
st                            └─────────────────────
1104  
src  
typ  
doc  
txt  
par  
pid  
st   
1105  theorem vector_nth' {n} : primrec (@vector.nth α n) := of_equiv_symm
id                             └─────┘   └────────┘       └───────────┘
src                            └─────┘   └────────┘         └───────────┘
typ                            └─────┘   └────────┘       └───────────┘
doc                            └─────┘
1106  
1107  theorem vector_of_fn' {n} : primrec (@vector.of_fn α n) := of_equiv
id                               └─────┘   └──────────┘       └──────┘
src                              └─────┘   └──────────┘         └──────┘
typ                              └─────┘   └──────────┘       └──────┘
doc                              └─────┘
1108  
1109  theorem fin_app {n} : primrec₂ (@id (fin n → σ)) :=
id                         └──────┘   └┘  └─┘    
src                        └──────┘   └┘  └─┘
typ                        └──────┘   └┘  └─┘    
doc                        └──────┘
1110  (vector_nth.comp (vector_of_fn'.comp fst) snd).of_eq $
id    └────────┘└───┘  └───────────┘└───┘ └─┘  └─┘ └───┘
src   └────────┘└───┘  └───────────┘└───┘ └─┘  └─┘ └───┘
typ   └────────┘└───┘  └───────────┘└───┘ └─┘  └─┘ └───┘
1111  λ ⟨v, i⟩, by simp
id     
src               └────
typ              └────
doc               └────
txt               └────
par               └────
pid                   
st               └─────
1112  
src  
typ  
doc  
txt  
par  
pid  
st   
1113  theorem fin_curry₁ {n} {f : fin n → α → σ} : primrec₂ f ↔ ∀ i, primrec (f i) :=
id                               └─┘           └──────┘       └─────┘   
src                              └─┘              └──────┘         └─────┘
typ                              └─┘           └──────┘       └─────┘   
doc                                               └──────┘          └─────┘
1114  ⟨λ h i, h.comp (const i) primrec.id,
id         └───┘  └───┘   └────────┘
src           └───┘  └───┘    └────────┘
typ        └───┘  └───┘   └────────┘
1115   λ h, (vector_nth.comp ((vector_of_fn h).comp snd) fst).of_eq $ λ a, by simp⟩
id         └────────┘└───┘   └──────────┘  └──┘  └─┘  └─┘ └───┘      
src         └────────┘└───┘   └──────────┘   └──┘  └─┘  └─┘ └───┘            └──┘
typ        └────────┘└───┘   └──────────┘  └──┘  └─┘  └─┘ └───┘           └──┘
doc                                                                          └──┘
txt                                                                          └──┘
par                                                                          └──┘
st                                                                          └───┘
1116  
1117  theorem fin_curry {n} {f : α → fin n → σ} : primrec f ↔ primrec₂ f :=
id                                 └─┘        └─────┘   └──────┘ 
src                                 └─┘          └─────┘    └──────┘
typ                                └─┘        └─────┘   └──────┘ 
doc                                              └─────┘     └──────┘
1118  ⟨λ h, fin_app.comp (h.comp fst) snd,
id        └─────┘└───┘  └───┘ └─┘  └─┘
src        └─────┘└───┘   └───┘ └─┘  └─┘
typ       └─────┘└───┘  └───┘ └─┘  └─┘
1119   λ h, (vector_nth'.comp (vector_of_fn (λ i,
id         └─────────┘└───┘  └──────────┘    
src         └─────────┘└───┘  └──────────┘
typ        └─────────┘└───┘  └──────────┘    
1120      show primrec (λ a, f a i), from
id            └─────┘        
src           └─────┘
typ           └─────┘        
doc           └─────┘
1121      h.comp primrec.id (const i)))).of_eq $
id       └───┘ └────────┘  └───┘     └───┘
src       └───┘ └────────┘  └───┘      └───┘
typ      └───┘ └────────┘  └───┘     └───┘
1122    λ a, by funext i; simp⟩
id       
src            └──────┘  └──┘
typ           └──────┘  └──┘
doc            └──────┘  └──┘
txt            └──────┘  └──┘
par            └──────┘  └──┘
pid                  └┘
st            └─────────────┘
1123  
1124  end primrec
1125  
1126  namespace nat
1127  open vector
1128  
1129  /-- An alternative inductive definition of `primrec` which
1130    does not use the pairing function on ℕ, and so has to
1131    work with n-ary functions on ℕ instead of unary functions.
1132    We prove that this is equivalent to the regular notion
1133    in `to_prim` and `of_prim`. -/
1134  inductive primrec' : ∀ {n}, (vector ℕ n → ℕ) → Prop
id                               └────┘    
src                               └────┘      
typ                              └────┘    
1135  | zero : @primrec' 0 (λ _, 0)
id                           
typ                          
1136  | succ : @primrec' 1 (λ v, succ v.head)
id                             └──┘ └───┘
src                             └──┘  └───┘
typ                            └──┘ └───┘
1137  | nth {n} (i : fin n) : primrec' (λ v, v.nth i)
id                 └─┘                   └──┘ 
src                 └─┘                      └──┘
typ                └─┘                   └──┘ 
1138  | comp {m n f} (g : fin n → vector ℕ m → ℕ) :
id                    └─┘   └────┘     
src                      └─┘     └────┘      
typ                   └─┘   └────┘     
1139    primrec' f → (∀ i, primrec' (g i)) →
id     └──────┘                    
typ    └──────┘                    
1140    primrec' (λ a, f (of_fn (λ i, g i a)))
id                     └───┘        
src                      └───┘
typ                    └───┘        
1141  | prec {n f g} : @primrec' n f → @primrec' (n+2) g →
id                  └──────┘      └──────┘     
src                                               
typ                 └──────┘      └──────┘     
1142    primrec' (λ v : vector ℕ (n+1),
id                     └────┘   
src                    └────┘    
typ                    └────┘   
1143      v.head.elim (f v.tail) (λ y IH, g (y :: IH :: v.tail)))
id       └───┘└───┘   └───┘      └┘     └┘ └┘ └┘ └───┘
src       └───┘└───┘     └───┘                └┘    └┘  └───┘
typ      └───┘└───┘   └───┘      └┘     └┘ └┘ └┘ └───┘
1144  
1145  end nat
1146  
1147  namespace nat.primrec'
1148  open vector primrec nat (primrec') nat.primrec'
1149  hide ite
1150  
1151  theorem to_prim {n f} (pf : @primrec' n f) : primrec f :=
id                                └──────┘      └─────┘ 
src                               └──────┘        └─────┘
typ                               └──────┘      └─────┘ 
doc                               └──────┘        └─────┘
1152  begin
st   └─────
1153    induction pf,
id               └┘
src    └────────┘
typ    └────────┘└┘
doc    └────────┘
txt    └────────┘
par    └────────┘
pid             
st   ─────────────┘└─
1154    case nat.primrec'.zero { exact const 0 },
id                                    └───┘
src    └───────────────────────┘└────┘└───┘└─┘
typ    └───────────────────────┘└────┘└───┘└─┘
doc    └───────────────────────┘└────┘     └─┘
txt    └───────────────────────┘└────┘     └─┘
par    └───────────────────────┘└────┘     └─┘
pid        └────────────────┘└──────┘     └──┘
st   ─────────────────────────┘└─────────────┘└┘
1155    case nat.primrec'.succ { exact primrec.succ.comp vector_head },
id                                    └───────────────┘ └─────────┘
src    └───────────────────────┘└────┘└───────────────┘└─────────┘
typ    └───────────────────────┘└────┘└───────────────┘└─────────┘
doc    └───────────────────────┘└────┘                            
txt    └───────────────────────┘└────┘                            
par    └───────────────────────┘└────┘                            
pid        └────────────────┘└──────┘                            └┘
st   ─────────────────────────┘└───────────────────────────────────┘└┘
1156    case nat.primrec'.nth : n i {
src    └─────────────────────────────
typ    └─────────────────────────────
doc    └─────────────────────────────
txt    └─────────────────────────────
par    └─────────────────────────────
pid        └───────────────┘└────┘└──
st   ──────────────────────────────┘
1157      exact vector_nth.comp primrec.id (const i) },
id             └─────────────┘ └────────┘  └───┘ 
src  ───┘└────┘└─────────────┘└────────┘ └───┘ └┘
typ  ───┘└────┘└─────────────┘└────────┘ └───┘└┘
doc  ───┘└────┘                                └┘
txt  ───┘└────┘                                └┘
par  ───┘└────┘                                └┘
pid  ─────────┘                                └─┘
st   ──────────────────────────────────────────────┘└┘
1158    case nat.primrec'.comp : m n f g _ _ hf hg {
src    └────────────────────────────────────────────
typ    └────────────────────────────────────────────
doc    └────────────────────────────────────────────
txt    └────────────────────────────────────────────
par    └────────────────────────────────────────────
pid        └────────────────┘└──────────────────┘└──
st   ─────────────────────────────────────────────┘
1159      exact hf.comp (vector_of_fn (λ i, hg i)) },
id             └─────┘  └──────────┘       └┘
src  ───┘└────┘└─────┘ └──────────┘  └──┘   └─┘
typ  ───┘└────┘└─────┘ └──────────┘  └──┘└┘ └─┘
doc  ───┘└────┘                      └──┘   └─┘
txt  ───┘└────┘                      └──┘   └─┘
par  ───┘└────┘                      └──┘   └─┘
pid  ─────────┘                      └──┘   └──┘
st   ────────────────────────────────────────────┘└┘
1160    case nat.primrec'.prec : n f g _ _ hf hg {
src    └──────────────────────────────────────────
typ    └──────────────────────────────────────────
doc    └──────────────────────────────────────────
txt    └──────────────────────────────────────────
par    └──────────────────────────────────────────
pid        └────────────────┘└────────────────┘└──
st   ───────────────────────────────────────────┘
1161      exact nat_elim' vector_head (hf.comp vector_tail) (hg.comp $
id             └───────┘ └─────────┘  └─────┘               └─────┘
src  ───┘└────┘└───────┘└─────────┘ └─────┘           └┘ └─────┘ 
typ  ───┘└────┘└───────┘└─────────┘ └─────┘           └┘ └─────┘ 
doc  ───┘└────┘                                       └┘         
txt  ───┘└────┘                                       └┘         
par  ───┘└────┘                                       └┘         
pid  ─────────┘                                       └┘         
st   ─────────────────────────────────────────────────────────────────
1162        vector_cons.comp (fst.comp snd) $
id                           └──────┘
src  ─────┘                 └──────┘   └┘ 
typ  ─────┘                 └──────┘   └┘ 
doc  ─────┘                            └┘ 
txt  ─────┘                            └┘ 
par  ─────┘                            └┘ 
pid  ─────┘                            └┘ 
st   ────────────────────────────────────────
1163        vector_cons.comp (snd.comp snd) $
id         └──────────────┘  └──────┘ └─┘
src  ─────┘└──────────────┘ └──────┘└─┘└┘ 
typ  ─────┘└──────────────┘ └──────┘└─┘└┘ 
doc  ─────┘                            └┘ 
txt  ─────┘                            └┘ 
par  ─────┘                            └┘ 
pid  ─────┘                            └┘ 
st   ────────────────────────────────────────
1164        (@vector_tail _ _ (n+1)).comp fst).to₂ },
id           └─────────┘               └─┘
src  ─────┘  └─────────┘└───┘  └───────┘└─┘└────┘
typ  ─────┘  └─────────┘└───┘ └───────┘└─┘└────┘
doc  ─────┘             └───┘   └───────┘   └────┘
txt  ─────┘             └───┘   └───────┘   └────┘
par  ─────┘             └───┘   └───────┘   └────┘
pid  ─────┘             └───┘   └───────┘   └─────┘
st   ────────────────────────────────────────────┘└──
1165  end
st   ──┘
1166  
1167  theorem of_eq {n} {f g : vector ℕ n → ℕ}
id                            └────┘     
src                           └────┘      
typ                           └────┘     
1168    (hf : primrec' f) (H : ∀ i, f i = g i) : primrec' g :=
id           └──────┘                    └──────┘ 
src          └──────┘                          └──────┘
typ          └──────┘                    └──────┘ 
doc          └──────┘                           └──────┘
1169  (funext H : f = g) ▸ hf
id    └────┘         └┘
src   └────┘           
typ   └────┘         └┘
1170  
1171  theorem const {n} : ∀ m, @primrec' n (λ v, m)
id                            └──────┘       
src                            └──────┘
typ                           └──────┘       
doc                            └──────┘
1172  | 0     := zero.comp fin.elim0 (λ i, i.elim0)
id              └──┘└───┘ └───────┘      └────┘
src             └───────┘ └───────┘        └────┘
typ             └──┘└───┘ └───────┘      └────┘
1173  | (m+1) := succ.comp _ (λ i, const m)
id            └──┘└───┘        └───┘
src            └───────┘
typ           └──┘└───┘        └───┘
1174  
1175  theorem head {n : ℕ} : @primrec' n.succ head :=
id                          └──────┘ └───┘ └──┘
src                         └──────┘  └───┘ └──┘
typ                         └──────┘ └───┘ └──┘
doc                          └──────┘
1176  (nth 0).of_eq $ λ v, by simp [nth_zero]
id    └─┘   └───┘                 └──────┘
src   └─┘   └───┘            └────┘└──────┘└─
typ   └─┘   └───┘           └────┘└──────┘└─
doc                          └────┘        └─
txt                          └────┘        └─
par                          └────┘        └─
pid                                      
st                          └────────────────
1177  
src  
typ  
doc  
txt  
par  
pid  
st   
1178  theorem tail {n f} (hf : @primrec' n f) : @primrec' n.succ (λ v, f v.tail) :=
id                             └──────┘       └──────┘ └───┘       └───┘
src                            └──────┘         └──────┘  └───┘          └───┘
typ                            └──────┘       └──────┘ └───┘       └───┘
doc                            └──────┘         └──────┘
1179  (hf.comp _ (λ i, @nth _ i.succ)).of_eq $
id    └┘└───┘         └─┘   └───┘  └───┘
src     └───┘          └─┘    └───┘  └───┘
typ   └┘└───┘         └─┘   └───┘  └───┘
1180  λ v, by rw [← of_fn_nth v.tail]; congr; funext i; simp
id                └───────┘ └────┘
src          └────┘└───────┘└────┘  └───┘  └──────┘  └────
typ         └────┘└───────┘└────┘  └───┘  └──────┘  └────
doc          └────┘                        └──────┘  └────
txt          └────┘                 └───┘  └──────┘  └────
par          └────┘                 └───┘  └──────┘  └────
pid            └──┘                              └┘      
st          └─────────────────────┘└───────────────────────
1181  
src  
typ  
doc  
txt  
par  
pid  
st   
1182  def vec {n m} (f : vector ℕ n → vector ℕ m) :=
id                      └────┘     └────┘  
src                     └────┘      └────┘ 
typ                     └────┘     └────┘  
1183  ∀ i, primrec' (λ v, (f v).nth i)
id       └──────┘         └─┘  
src       └──────┘            └─┘
typ      └──────┘         └─┘  
doc       └──────┘
1184  
1185  protected theorem nil {n} : @vec n 0 (λ _, nil) := λ i, i.elim0
id                                └─┘         └─┘         └────┘
src                               └─┘           └─┘           └────┘
typ                               └─┘         └─┘         └────┘
1186  
1187  protected theorem cons {n m f g}
1188    (hf : @primrec' n f) (hg : @vec n m g) :
id            └──────┘           └─┘   
src           └──────┘             └─┘
typ           └──────┘           └─┘   
doc           └──────┘
1189    vec (λ v, f v :: g v) :=
id     └─┘        └┘  
src    └─┘           └┘
typ    └─┘        └┘  
1190  λ i, fin.cases (by simp *) (λ i, by simp [hg i]) i
id       └───────┘                           └┘    
src       └───────┘     └────┘           └────┘   
typ      └───────┘     └────┘          └────┘└┘  
doc                     └────┘           └────┘   
txt                     └────┘           └────┘   
par                     └────┘           └────┘   
pid                                           
st                     └─────┘          └──────────┘
1191  
1192  theorem idv {n} : @vec n n id := nth
id                      └─┘   └┘    └─┘
src                     └─┘     └┘    └─┘
typ                     └─┘   └┘    └─┘
1193  
1194  theorem comp' {n m f g}
1195    (hf : @primrec' m f) (hg : @vec n m g) :
id            └──────┘           └─┘   
src           └──────┘             └─┘
typ           └──────┘           └─┘   
doc           └──────┘
1196    primrec' (λ v, f (g v)) :=
id     └──────┘         
src    └──────┘
typ    └──────┘         
doc    └──────┘
1197  (hf.comp _ hg).of_eq $ λ v, by simp
id    └┘└───┘   └┘ └───┘      
src     └───┘      └───┘            └────
typ   └┘└───┘   └┘ └───┘           └────
doc                                 └────
txt                                 └────
par                                 └────
pid                                     
st                                 └─────
1198  
src  
typ  
doc  
txt  
par  
pid  
st   
1199  theorem comp₁ (f : ℕ → ℕ) (hf : @primrec' 1 (λ v, f v.head))
id                                  └──────┘         └───┘
src                                 └──────┘            └───┘
typ                                 └──────┘         └───┘
doc                                   └──────┘
1200    {n g} (hg : @primrec' n g) : primrec' (λ v, f (g v)) :=
id                  └──────┘      └──────┘         
src                 └──────┘        └──────┘
typ                 └──────┘      └──────┘         
doc                 └──────┘        └──────┘
1201  hf.comp _ (λ i, hg)
id   └┘└───┘        └┘
src    └───┘
typ  └┘└───┘        └┘
1202  
1203  theorem comp₂ (f : ℕ → ℕ → ℕ)
id                            
src                           
typ                           
1204    (hf : @primrec' 2 (λ v, f v.head v.tail.head))
id            └──────┘         └───┘ └───┘└───┘
src           └──────┘            └───┘  └───┘└───┘
typ           └──────┘         └───┘ └───┘└───┘
doc           └──────┘
1205    {n g h} (hg : @primrec' n g) (hh : @primrec' n h) :
id                    └──────┘           └──────┘  
src                   └──────┘             └──────┘
typ                   └──────┘           └──────┘  
doc                   └──────┘             └──────┘
1206    primrec' (λ v, f (g v) (h v)) :=
id     └──────┘             
src    └──────┘
typ    └──────┘             
doc    └──────┘
1207  by simpa using hf.comp' (hg.cons $ hh.cons primrec'.nil)
id                  └──────┘  └─────┘   └─────┘ └──────────┘
src     └──────────┘└──────┘ └─────┘ └─────┘└──────────┘└─
typ     └──────────┘└──────┘ └─────┘ └─────┘└──────────┘└─
doc     └──────────┘                                    └─
txt     └──────────┘                                    └─
par     └──────────┘                                    └─
pid          └────┘                                    
st     └──────────────────────────────────────────────────────
1208  
src  
typ  
doc  
txt  
par  
pid  
st   
1209  theorem prec' {n f g h}
1210    (hf : @primrec' n f) (hg : @primrec' n g) (hh : @primrec' (n+2) h) :
id            └──────┘           └──────┘           └──────┘     
src           └──────┘             └──────┘             └──────┘   
typ           └──────┘           └──────┘           └──────┘     
doc           └──────┘             └──────┘             └──────┘
1211    @primrec' n (λ v, (f v).elim (g v)
id      └──────┘          └──┘    
src     └──────┘              └──┘
typ     └──────┘          └──┘    
doc     └──────┘
1212      (λ (y IH : ℕ), h (y :: IH :: v))) :=
id                        └┘ └┘ └┘ 
src                         └┘    └┘
typ                       └┘ └┘ └┘ 
1213  by simpa using comp' (prec hg hh) (hf.cons idv)
id                  └───┘  └──┘ └┘ └┘   └─────┘ └─┘
src     └──────────┘└───┘ └──┘    └┘ └─────┘└─┘└─
typ     └──────────┘└───┘ └──┘└┘└┘└┘ └─────┘└─┘└─
doc     └──────────┘              └┘           └─
txt     └──────────┘              └┘           └─
par     └──────────┘              └┘           └─
pid          └────┘              └┘           
st     └─────────────────────────────────────────────
1214  
src  
typ  
doc  
txt  
par  
pid  
st   
1215  theorem pred : @primrec' 1 (λ v, v.head.pred) :=
id                   └──────┘        └───┘└───┘
src                  └──────┘          └───┘└───┘
typ                  └──────┘        └───┘└───┘
doc                  └──────┘
1216  (prec' head (const 0) head).of_eq $
id    └───┘ └──┘  └───┘    └──┘ └───┘
src   └───┘ └──┘  └───┘    └──┘ └───┘
typ   └───┘ └──┘  └───┘    └──┘ └───┘
1217  λ v, by simp; cases v.head; refl
id                      └────┘
src          └──┘  └────┘└────┘  └────
typ         └──┘  └────┘└────┘  └────
doc          └──┘  └────┘        └────
txt          └──┘  └────┘        └────
par          └──┘  └────┘        └────
pid                                 
st          └─────────────────────────
1218  
src  
typ  
doc  
txt  
par  
pid  
st   
1219  theorem add : @primrec' 2 (λ v, v.head + v.tail.head) :=
id                  └──────┘        └───┘  └───┘└───┘
src                 └──────┘          └───┘   └───┘└───┘
typ                 └──────┘        └───┘  └───┘└───┘
doc                 └──────┘
1220  (prec head (succ.comp₁ _ (tail head))).of_eq $
id    └──┘ └──┘  └──┘└────┘    └──┘ └──┘   └───┘
src   └──┘ └──┘  └──┘└────┘    └──┘ └──┘   └───┘
typ   └──┘ └──┘  └──┘└────┘    └──┘ └──┘   └───┘
1221  λ v, by simp; induction v.head; simp [*, nat.succ_add]
id                          └────┘           └──────────┘
src          └──┘  └────────┘└────┘  └───────┘└──────────┘└─
typ         └──┘  └────────┘└────┘  └───────┘└──────────┘└─
doc          └──┘  └────────┘        └───────┘            └─
txt          └──┘  └────────┘        └───────┘            └─
par          └──┘  └────────┘        └───────┘            └─
pid                                     └──┘            
st          └───────────────────────────────────────────────
1222  
src  
typ  
doc  
txt  
par  
pid  
st   
1223  theorem sub : @primrec' 2 (λ v, v.head - v.tail.head) :=
id                  └──────┘        └───┘  └───┘└───┘
src                 └──────┘          └───┘   └───┘└───┘
typ                 └──────┘        └───┘  └───┘└───┘
doc                 └──────┘
1224  begin
st   └─────
1225    suffices, simpa using comp₂ (λ a b, b - a) this (tail head) head,
id                           └───┘               └──┘  └──┘       └──┘
src    └──────┘  └──────────┘└───┘  └────┘  └┘     └──┘    └┘└──┘
typ    └──────┘  └──────────┘└───┘  └────┘  └┘└──┘ └──┘    └┘└──┘
doc    └──────┘  └──────────┘       └────┘   └┘             └┘
txt    └──────┘  └──────────┘       └────┘   └┘             └┘
par    └──────┘  └──────────┘       └────┘   └┘             └┘
pid    └──────┘       └────┘       └────┘   └┘             └┘
st   ─────────┘└──────────────────────────────────────────────────────┘└─
1226    refine (prec head (pred.comp₁ _ (tail head))).of_eq (λ v, _),
id             └──┘       └────────┘    └──┘ └──┘
src    └─────┘ └──┘     └────────┘└─┘ └──┘└──┘└────────┘  └────┘
typ    └─────┘ └──┘     └────────┘└─┘ └──┘└──┘└────────┘  └────┘
doc    └─────┘                    └─┘         └────────┘  └────┘
txt    └─────┘                    └─┘         └────────┘  └────┘
par    └─────┘                    └─┘         └────────┘  └────┘
pid                              └─┘         └────────┘  └────┘
st   ─────────────────────────────────────────────────────────────┘└─
1227    simp, induction v.head; simp [*, nat.sub_succ]
id                     └────┘           └──────────┘
src    └──┘  └────────┘└────┘  └───────┘└──────────┘└┘
typ    └──┘  └────────┘└────┘  └───────┘└──────────┘└┘
doc    └──┘  └────────┘        └───────┘            └┘
txt    └──┘  └────────┘        └───────┘            └┘
par    └──┘  └────────┘        └───────┘            └┘
pid                               └──┘            
st   ─────┘└─────────────────────────────────────────┘
1228  end
st   └─┘
1229  
1230  theorem mul : @primrec' 2 (λ v, v.head * v.tail.head) :=
id                  └──────┘        └───┘  └───┘└───┘
src                 └──────┘          └───┘   └───┘└───┘
typ                 └──────┘        └───┘  └───┘└───┘
doc                 └──────┘
1231  (prec (const 0) (tail (add.comp₂ _ (tail head) (head)))).of_eq $
id    └──┘  └───┘     └──┘  └─┘└────┘    └──┘ └──┘   └──┘    └───┘
src   └──┘  └───┘     └──┘  └─┘└────┘    └──┘ └──┘   └──┘    └───┘
typ   └──┘  └───┘     └──┘  └─┘└────┘    └──┘ └──┘   └──┘    └───┘
1232  λ v, by simp; induction v.head; simp [*, nat.succ_mul]; rw add_comm
id                          └────┘           └──────────┘      └──────┘
src          └──┘  └────────┘└────┘  └───────┘└──────────┘  └─┘└──────┘
typ         └──┘  └────────┘└────┘  └───────┘└──────────┘  └─┘└──────┘
doc          └──┘  └────────┘        └───────┘              └─┘        
txt          └──┘  └────────┘        └───────┘              └─┘        
par          └──┘  └────────┘        └───────┘              └─┘        
pid                                     └──┘                        
st          └──────────────────────────────────────────────────┘└──────┘
1233  
src  
typ  
doc  
txt  
par  
pid  
st   
1234  theorem if_lt {n a b f g}
1235    (ha : @primrec' n a) (hb : @primrec' n b)
id            └──────┘           └──────┘  
src           └──────┘             └──────┘
typ           └──────┘           └──────┘  
doc           └──────┘             └──────┘
1236    (hf : @primrec' n f) (hg : @primrec' n g) :
id            └──────┘           └──────┘  
src           └──────┘             └──────┘
typ           └──────┘           └──────┘  
doc           └──────┘             └──────┘
1237    @primrec' n (λ v, if a v < b v then f v else g v) :=
id      └──────┘                            
src     └──────┘                
typ     └──────┘                            
doc     └──────┘
1238  (prec' (sub.comp₂ _ hb ha) hg (tail $ tail hf)).of_eq $
id    └───┘  └─┘└────┘   └┘ └┘  └┘  └──┘   └──┘ └┘  └───┘
src   └───┘  └─┘└────┘              └──┘   └──┘     └───┘
typ   └───┘  └─┘└────┘   └┘ └┘  └┘  └──┘   └──┘ └┘  └───┘
1239  λ v, begin
id     
typ    
st        └─────
1240    cases e : b v - a v,
id                    
src    └────┘ └─┘   
typ    └────┘ └─┘ 
doc    └────┘ └─┘    
txt    └────┘ └─┘    
par    └────┘ └─┘    
pid          └─┘    
st   ────────────────────┘└─
1241    { simp [not_lt.2 (nat.le_of_sub_eq_zero e)] },
id             └────┘    └───────────────────┘ 
src      └────┘└────┘└─┘ └───────────────────┘ └─┘
typ      └────┘└────┘└─┘ └───────────────────┘└─┘
doc      └────┘      └─┘                       └─┘
txt      └────┘      └─┘                       └─┘
par      └────┘      └─┘                       └─┘
pid                └─┘                       └┘
st   ───┘└────────────────────────────────────────┘└┘
1242    { simp [nat.lt_of_sub_eq_succ e] }
id             └───────────────────┘ 
src      └────┘└───────────────────┘ └┘
typ      └────┘└───────────────────┘└┘
doc      └────┘                      └┘
txt      └────┘                      └┘
par      └────┘                      └┘
pid                                
st   ──────────────────────────────────┘└─
1243  end
st   ──┘
1244  
1245  theorem mkpair : @primrec' 2 (λ v, v.head.mkpair v.tail.head) :=
id                     └──────┘        └───┘└─────┘ └───┘└───┘
src                    └──────┘          └───┘└─────┘  └───┘└───┘
typ                    └──────┘        └───┘└─────┘ └───┘└───┘
doc                    └──────┘               └─────┘
1246  if_lt head (tail head)
id   └───┘ └──┘  └──┘ └──┘
src  └───┘ └──┘  └──┘ └──┘
typ  └───┘ └──┘  └──┘ └──┘
1247    (add.comp₂ _ (tail $ mul.comp₂ _ head head) head)
id      └─┘└────┘    └──┘   └─┘└────┘   └──┘ └──┘  └──┘
src     └─┘└────┘    └──┘   └─┘└────┘   └──┘ └──┘  └──┘
typ     └─┘└────┘    └──┘   └─┘└────┘   └──┘ └──┘  └──┘
1248    (add.comp₂ _ (add.comp₂ _
id      └─┘└────┘    └─┘└────┘
src     └─┘└────┘    └─┘└────┘
typ     └─┘└────┘    └─┘└────┘
1249      (mul.comp₂ _ head head) head) (tail head))
id        └─┘└────┘   └──┘ └──┘  └──┘   └──┘ └──┘
src       └─┘└────┘   └──┘ └──┘  └──┘   └──┘ └──┘
typ       └─┘└────┘   └──┘ └──┘  └──┘   └──┘ └──┘
1250  
1251  protected theorem encode : ∀ {n}, @primrec' n encode
id                                    └──────┘  └────┘
src                                     └──────┘   └────┘
typ                                   └──────┘  └────┘
doc                                     └──────┘
1252  | 0     := (const 0).of_eq (λ v, by rw v.eq_nil; refl)
id               └───┘   └───┘     
src              └───┘   └───┘           └─┘          └──┘
typ              └───┘   └───┘          └─┘└──────┘  └──┘
doc                                      └─┘          └──┘
txt                                      └─┘          └──┘
par                                      └─┘          └──┘
pid                                        
st                                      └────────────────┘
1253  | (n+1) := (succ.comp₁ _ (mkpair.comp₂ _ head (tail encode)))
id              └──┘└────┘    └────┘└────┘   └──┘  └──┘ └────┘
src             └──┘└────┘    └────┘└────┘   └──┘  └──┘
typ             └──┘└────┘    └────┘└────┘   └──┘  └──┘ └────┘
1254    .of_eq $ λ ⟨a::l, e⟩, rfl
id     └───┘       └┘       └─┘
src    └───┘        └┘       └─┘
typ    └───┘       └┘       └─┘
1255  
1256  theorem sqrt : @primrec' 1 (λ v, v.head.sqrt) :=
id                   └──────┘        └───┘└───┘
src                  └──────┘          └───┘└───┘
typ                  └──────┘        └───┘└───┘
doc                  └──────┘               └───┘
1257  begin
st   └─────
1258    suffices H : ∀ n : ℕ, n.sqrt = n.elim 0 (λ x y,
id                            └───┘   └───┘
src    └───────────┘ └───┘   └───┘ └───┘└─┘  └─────
typ    └───────────┘ └───┘   └───┘ └───┘└─┘  └─────
doc    └───────────┘ └───┘   └───┘       └─┘  └─────
txt    └───────────┘ └───┘               └─┘  └─────
par    └───────────┘ └───┘               └─┘  └─────
pid    └────────┘└─┘ └───┘               └─┘  └─────
st   ──────────────────────────────────────────────────
1259      if x.succ < y.succ*y.succ then y else y.succ),
id                   └───┘
src  ───┘  └──────┘ └───┘      └────┘ └────┘      
typ  ───┘  └──────┘ └───┘      └────┘ └────┘      
doc  ───┘  └──────┘              └────┘ └────┘      
txt  ───┘  └──────┘              └────┘ └────┘      
par  ───┘  └──────┘              └────┘ └────┘      
pid  ───┘  └──────┘              └────┘ └────┘      
st   ────────────────────────────────────────────────┘└─
1260    { simp [H],
id             
src      └────┘ 
typ      └────┘
doc      └────┘ 
txt      └────┘ 
par      └────┘ 
pid           
st   ───┘└──────┘└─
1261      have := @prec' 1 _ _ (λ v,
id                └───┘
src      └──────┘ └───┘└─────┘  └───
typ      └──────┘ └───┘└─────┘  └───
doc      └──────┘      └─────┘  └───
txt      └──────┘      └─────┘  └───
par      └──────┘      └─────┘  └───
pid      └───┘└─┘      └─────┘  └───
st   ───────────────────────────────
1262        by have x := v.head; have y := v.tail.head; from
id                      └────┘            └─────────┘
src  ─────┘  └─────────┘└────┘└──────────┘└─────────┘└┘└────
typ  ─────┘  └─────────┘└────┘└──────────┘└─────────┘└┘└────
doc  ─────┘  └─────────┘      └──────────┘           └┘└────
txt  ─────┘  └─────────┘      └──────────┘           └┘└────
par  ─────┘  └─────────┘      └──────────┘           └┘└────
pid  ─────┘  └─────────┘      └──────────┘           └──────
st   ───────┘└──────────────────────────────────────────────
1263        if x.succ < y.succ*y.succ then y else y.succ) head (const 0) _,
id                                               └────┘  └──┘  └───┘
src  ─────┘  └──────┘              └────┘ └────┘└────┘└┘└──┘ └───┘└───┘
typ  ─────┘  └──────┘              └────┘ └────┘└────┘└┘└──┘ └───┘└───┘
doc  ─────┘  └──────┘              └────┘ └────┘      └┘          └───┘
txt  ─────┘  └──────┘              └────┘ └────┘      └┘          └───┘
par  ─────┘  └──────┘              └────┘ └────┘      └┘          └───┘
pid  ─────┘  └──────┘              └────┘ └────┘      └┘          └───┘
st   ─────────────────────────────────────────────────┘└────────────────┘└─
1264      { convert this, funext, congr, funext x y, congr; simp },
id                 └──┘
src        └──────┘      └────┘  └───┘  └────────┘  └───┘  └───┘
typ        └──────┘└──┘  └────┘  └───┘  └────────┘  └───┘  └───┘
doc        └──────┘      └────┘         └────────┘         └───┘
txt        └──────┘      └────┘  └───┘  └────────┘  └───┘  └───┘
par        └──────┘      └────┘  └───┘  └────────┘  └───┘  └───┘
pid                                          └──┘             
st   ─────┘└──────────┘└──────┘└─────┘└──────────┘└────────────┘└┘
1265      have x1 := succ.comp₁ _ head,
id                  └────────┘   └──┘
src      └─────────┘└────────┘└─┘└──┘
typ      └─────────┘└────────┘└─┘└──┘
doc      └─────────┘          └─┘
txt      └─────────┘          └─┘
par      └─────────┘          └─┘
pid      └─────┘└─┘          └─┘
st   ───────────────────────────────┘└─
1266      have y1 := succ.comp₁ _ (tail head),
id                  └────────┘    └──┘ └──┘
src      └─────────┘└────────┘└─┘ └──┘└──┘
typ      └─────────┘└────────┘└─┘ └──┘└──┘
doc      └─────────┘          └─┘         
txt      └─────────┘          └─┘         
par      └─────────┘          └─┘         
pid      └─────┘└─┘          └─┘         
st   ──────────────────────────────────────┘└─
1267      exact if_lt x1 (mul.comp₂ _ y1 y1) (tail head) y1 },
id             └───┘ └┘  └───────┘           └──┘ └──┘  └┘
src      └────┘└───┘   └───────┘└─┘    └┘ └──┘└──┘└┘  
typ      └────┘└───┘└┘ └───────┘└─┘    └┘ └──┘└──┘└┘└┘
doc      └────┘                 └─┘    └┘         └┘  
txt      └────┘                 └─┘    └┘         └┘  
par      └────┘                 └─┘    └┘         └┘  
pid                            └─┘    └┘         └┘  
st   ─────────────────────────────────────────────────────┘└┘
1268    intro, symmetry,
src    └───┘  └──────┘
typ    └───┘  └──────┘
doc    └───┘  └──────┘
txt    └───┘  └──────┘
par    └───┘  └──────┘
st   ──────┘└────────┘└─
1269    induction n with n IH, {refl},
id               
src    └────────┘ └────────┘   └──┘
typ    └────────┘└────────┘   └──┘
doc    └────────┘ └────────┘   └──┘
txt    └────────┘ └────────┘   └──┘
par    └────────┘ └────────┘   └──┘
pid              └───────┘
st   ──────────────────────┘└─────┘└┘
1270    dsimp, rw IH, split_ifs,
id               └┘
src    └───┘  └─┘    └───────┘
typ    └───┘  └─┘└┘  └───────┘
doc    └───┘  └─┘    └───────┘
txt    └───┘  └─┘    └───────┘
par    └───┘  └─┘    └───────┘
pid             
st   ──────┘└─────┘└─────────┘└─
1271    { exact le_antisymm (nat.sqrt_le_sqrt (nat.le_succ _))
id             └─────────┘  └──────────────┘  └─────────┘
src      └────┘└─────────┘ └──────────────┘ └─────────┘└────
typ      └────┘└─────────┘ └──────────────┘ └─────────┘└────
doc      └────┘                                        └────
txt      └────┘                                        └────
par      └────┘                                        └────
pid                                                   └────
st   ───┘└────────────────────────────────────────────────────
1272        (nat.lt_succ_iff.1 $ nat.sqrt_lt.2 h) },
id          └─────────────┘     └─────────┘   
src  ─────┘ └─────────────┘└─┘ └─────────┘└─┘ └┘
typ  ─────┘ └─────────────┘└─┘ └─────────┘└─┘└┘
doc  ─────┘                └─┘            └─┘ └┘
txt  ─────┘                └─┘            └─┘ └┘
par  ─────┘                └─┘            └─┘ └┘
pid  ─────┘                └─┘            └─┘ 
st   ───────────────────────────────────────────┘└┘
1273    { exact nat.eq_sqrt.2 ⟨not_lt.1 h, nat.sqrt_lt.1 $
id             └─────────┘    └────┘     └─────────┘
src      └────┘└─────────┘└─┘ └────┘└─┘ └┘└─────────┘└─┘ 
typ      └────┘└─────────┘└─┘ └────┘└─┘└┘└─────────┘└─┘ 
doc      └────┘           └─┘       └─┘ └┘           └─┘ 
txt      └────┘           └─┘       └─┘ └┘           └─┘ 
par      └────┘           └─┘       └─┘ └┘           └─┘ 
pid                      └─┘       └─┘ └┘           └─┘ 
st   ─────────────────────────────────────────────────────
1274        nat.lt_succ_iff.2 $ nat.sqrt_succ_le_succ_sqrt _⟩ },
id         └─────────────┘     └────────────────────────┘
src  ─────┘└─────────────┘└─┘ └────────────────────────┘└──┘
typ  ─────┘└─────────────┘└─┘ └────────────────────────┘└──┘
doc  ─────┘               └─┘                           └──┘
txt  ─────┘               └─┘                           └──┘
par  ─────┘               └─┘                           └──┘
pid  ─────┘               └─┘                           └─┘
st   ───────────────────────────────────────────────────────┘└──
1275  end
st   ──┘
1276  
1277  theorem unpair₁ {n f} (hf : @primrec' n f) :
id                                └──────┘  
src                               └──────┘
typ                               └──────┘  
doc                               └──────┘
1278    @primrec' n (λ v, (f v).unpair.1) :=
id      └──────┘          └────┘ 
src     └──────┘              └────┘ 
typ     └──────┘          └────┘ 
doc     └──────┘              └────┘
1279  begin
st   └─────
1280    have s := sqrt.comp₁ _ hf,
id               └────────┘   └┘
src    └────────┘└────────┘└─┘
typ    └────────┘└────────┘└─┘└┘
doc    └────────┘          └─┘
txt    └────────┘          └─┘
par    └────────┘          └─┘
pid    └────┘└─┘          └─┘
st   ──────────────────────────┘└─
1281    have fss := sub.comp₂ _ hf (mul.comp₂ _ s s),
id                 └───────┘   └┘  └───────┘     
src    └──────────┘└───────┘└─┘   └───────┘└─┘  
typ    └──────────┘└───────┘└─┘└┘ └───────┘└─┘ 
doc    └──────────┘         └─┘            └─┘  
txt    └──────────┘         └─┘            └─┘  
par    └──────────┘         └─┘            └─┘  
pid    └──────┘└─┘         └─┘            └─┘  
st   ─────────────────────────────────────────────┘└─
1282    refine (if_lt fss s fss s).of_eq (λ v, _),
id             └───┘       └─┘ 
src    └─────┘ └───┘        └──────┘  └────┘
typ    └─────┘ └───┘    └─┘└──────┘  └────┘
doc    └─────┘              └──────┘  └────┘
txt    └─────┘              └──────┘  └────┘
par    └─────┘              └──────┘  └────┘
pid                        └──────┘  └────┘
st   ──────────────────────────────────────────┘└─
1283    simp [nat.unpair], split_ifs; refl
id           └────────┘
src    └────┘└────────┘  └───────┘  └───┘
typ    └────┘└────────┘  └───────┘  └───┘
doc    └────┘└────────┘  └───────┘  └───┘
txt    └────┘            └───────┘  └───┘
par    └────┘            └───────┘  └───┘
pid                                   
st   ──────────────────┘└────────────────┘
1284  end
st   └─┘
1285  
1286  theorem unpair₂ {n f} (hf : @primrec' n f) :
id                                └──────┘  
src                               └──────┘
typ                               └──────┘  
doc                               └──────┘
1287    @primrec' n (λ v, (f v).unpair.2) :=
id      └──────┘          └────┘ 
src     └──────┘              └────┘ 
typ     └──────┘          └────┘ 
doc     └──────┘              └────┘
1288  begin
st   └─────
1289    have s := sqrt.comp₁ _ hf,
id               └────────┘   └┘
src    └────────┘└────────┘└─┘
typ    └────────┘└────────┘└─┘└┘
doc    └────────┘          └─┘
txt    └────────┘          └─┘
par    └────────┘          └─┘
pid    └────┘└─┘          └─┘
st   ──────────────────────────┘└─
1290    have fss := sub.comp₂ _ hf (mul.comp₂ _ s s),
id                 └───────┘   └┘  └───────┘     
src    └──────────┘└───────┘└─┘   └───────┘└─┘  
typ    └──────────┘└───────┘└─┘└┘ └───────┘└─┘ 
doc    └──────────┘         └─┘            └─┘  
txt    └──────────┘         └─┘            └─┘  
par    └──────────┘         └─┘            └─┘  
pid    └──────┘└─┘         └─┘            └─┘  
st   ─────────────────────────────────────────────┘└─
1291    refine (if_lt fss s s (sub.comp₂ _ fss s)).of_eq (λ v, _),
id             └───┘          └───────┘   └─┘ 
src    └─────┘ └───┘      └───────┘└─┘    └───────┘  └────┘
typ    └─────┘ └───┘      └───────┘└─┘└─┘└───────┘  └────┘
doc    └─────┘                     └─┘    └───────┘  └────┘
txt    └─────┘                     └─┘    └───────┘  └────┘
par    └─────┘                     └─┘    └───────┘  └────┘
pid                               └─┘    └───────┘  └────┘
st   ──────────────────────────────────────────────────────────┘└─
1292    simp [nat.unpair], split_ifs; refl
id           └────────┘
src    └────┘└────────┘  └───────┘  └───┘
typ    └────┘└────────┘  └───────┘  └───┘
doc    └────┘└────────┘  └───────┘  └───┘
txt    └────┘            └───────┘  └───┘
par    └────┘            └───────┘  └───┘
pid                                   
st   ──────────────────┘└────────────────┘
1293  end
st   └─┘
1294  
1295  theorem of_prim : ∀ {n f}, primrec f → @primrec' n f :=
id                            └─────┘     └──────┘  
src                             └─────┘      └──────┘
typ                           └─────┘     └──────┘  
doc                             └─────┘      └──────┘
1296  suffices ∀ f, nat.primrec f → @primrec' 1 (λ v, f v.head), from
id                └─────────┘     └──────┘         └───┘
src                └─────────┘      └──────┘            └───┘
typ               └─────────┘     └──────┘         └───┘
doc                └─────────┘      └──────┘
1297  λ n f hf, (pred.comp₁ _ $ (this _ hf).comp₁
id       └┘   └──┘└────┘      └──┘   └┘ └───┘
src             └──┘└────┘                └───┘
typ      └┘   └──┘└────┘      └──┘   └┘ └───┘
1298    (λ m, encodable.encode $ (decode (vector ℕ n) m).map f)
id          └──────────────┘    └────┘  └────┘     └─┘  
src          └──────────────┘    └────┘  └────┘       └─┘
typ         └──────────────┘    └────┘  └────┘     └─┘  
1299      primrec'.encode).of_eq (λ i, by simp [encodek]),
id       └─────────────┘ └───┘                └─────┘
src      └─────────────┘ └───┘           └────┘└─────┘
typ      └─────────────┘ └───┘          └────┘└─────┘
doc                                      └────┘       
txt                                      └────┘       
par                                      └────┘       
pid                                                 
st                                      └─────────────┘
1300  λ f hf, begin
id      └┘
typ     └┘
st           └─────
1301    induction hf,
id               └┘
src    └────────┘
typ    └────────┘└┘
doc    └────────┘
txt    └────────┘
par    └────────┘
pid             
st   ─────────────┘└─
1302    case nat.primrec.zero { exact const 0 },
id                                   └───┘
src    └──────────────────────┘└────┘└───┘└─┘
typ    └──────────────────────┘└────┘└───┘└─┘
doc    └──────────────────────┘└────┘     └─┘
txt    └──────────────────────┘└────┘     └─┘
par    └──────────────────────┘└────┘     └─┘
pid        └───────────────┘└──────┘     └──┘
st   ────────────────────────┘└─────────────┘└┘
1303    case nat.primrec.succ { exact succ },
id                                   └──┘
src    └──────────────────────┘└────┘└──┘
typ    └──────────────────────┘└────┘└──┘
doc    └──────────────────────┘└────┘    
txt    └──────────────────────┘└────┘    
par    └──────────────────────┘└────┘    
pid        └───────────────┘└──────┘    └┘
st   ────────────────────────┘└──────────┘└┘
1304    case nat.primrec.left { exact unpair₁ head },
id                                   └─────┘ └──┘
src    └──────────────────────┘└────┘└─────┘└──┘
typ    └──────────────────────┘└────┘└─────┘└──┘
doc    └──────────────────────┘└────┘           
txt    └──────────────────────┘└────┘           
par    └──────────────────────┘└────┘           
pid        └───────────────┘└──────┘           └┘
st   ────────────────────────┘└──────────────────┘└┘
1305    case nat.primrec.right { exact unpair₂ head },
id                                    └─────┘ └──┘
src    └───────────────────────┘└────┘└─────┘└──┘
typ    └───────────────────────┘└────┘└─────┘└──┘
doc    └───────────────────────┘└────┘           
txt    └───────────────────────┘└────┘           
par    └───────────────────────┘└────┘           
pid        └────────────────┘└──────┘           └┘
st   ─────────────────────────┘└──────────────────┘└┘
1306    case nat.primrec.pair : f g _ _ hf hg {
src    └───────────────────────────────────────
typ    └───────────────────────────────────────
doc    └───────────────────────────────────────
txt    └───────────────────────────────────────
par    └───────────────────────────────────────
pid        └───────────────┘└──────────────┘└──
st   ────────────────────────────────────────┘
1307      exact mkpair.comp₂ _ hf hg },
id             └──────────┘   └┘ └┘
src  ───┘└────┘└──────────┘└─┘    
typ  ───┘└────┘└──────────┘└─┘└┘└┘
doc  ───┘└────┘            └─┘    
txt  ───┘└────┘            └─┘    
par  ───┘└────┘            └─┘    
pid  ─────────┘            └─┘    └┘
st   ──────────────────────────────┘└┘
1308    case nat.primrec.comp : f g _ _ hf hg {
src    └───────────────────────────────────────
typ    └───────────────────────────────────────
doc    └───────────────────────────────────────
txt    └───────────────────────────────────────
par    └───────────────────────────────────────
pid        └───────────────┘└──────────────┘└──
st   ────────────────────────────────────────┘
1309      exact hf.comp₁ _ hg },
id             └──────┘   └┘
src  ───┘└────┘└──────┘└─┘  
typ  ───┘└────┘└──────┘└─┘└┘
doc  ───┘└────┘        └─┘  
txt  ───┘└────┘        └─┘  
par  ───┘└────┘        └─┘  
pid  ─────────┘        └─┘  └┘
st   ───────────────────────┘└┘
1310    case nat.primrec.prec : f g _ _ hf hg {
src    └───────────────────────────────────────
typ    └───────────────────────────────────────
doc    └───────────────────────────────────────
txt    └───────────────────────────────────────
par    └───────────────────────────────────────
pid        └───────────────┘└──────────────┘└──
st   ────────────────────────────────────────┘
1311      simpa using prec' (unpair₂ head)
id                   └───┘  └─────┘
src  ───┘└──────────┘└───┘ └─────┘    └─
typ  ───┘└──────────┘└───┘ └─────┘    └─
doc  ───┘└──────────┘                 └─
txt  ───┘└──────────┘                 └─
par  ───┘└──────────┘                 └─
pid  ───────────────┘                 └─
st   ─────────────────────────────────────
1312        (hf.comp₁ _ (unpair₁ head))
id          └──────┘
src  ─────┘ └──────┘└─┘            └──
typ  ─────┘ └──────┘└─┘            └──
doc  ─────┘         └─┘            └──
txt  ─────┘         └─┘            └──
par  ─────┘         └─┘            └──
pid  ─────┘         └─┘            └──
st   ──────────────────────────────────
1313        (hg.comp₁ _ $ mkpair.comp₂ _ (unpair₁ $ tail $ tail head)
id          └──────┘                     └─────┘
src  ─────┘ └──────┘└─┘             └─┘ └─────┘              └─
typ  ─────┘ └──────┘└─┘             └─┘ └─────┘              └─
doc  ─────┘         └─┘             └─┘                      └─
txt  ─────┘         └─┘             └─┘                      └─
par  ─────┘         └─┘             └─┘                      └─
pid  ─────┘         └─┘             └─┘                      └─
st   ────────────────────────────────────────────────────────────────
1314          (mkpair.comp₂ _ head (tail head))) },
id            └──────────┘         └──┘ └──┘
src  ───────┘ └──────────┘└─┘     └──┘└──┘└──┘
typ  ───────┘ └──────────┘└─┘     └──┘└──┘└──┘
doc  ───────┘             └─┘             └──┘
txt  ───────┘             └─┘             └──┘
par  ───────┘             └─┘             └──┘
pid  ───────┘             └─┘             └───┘
st   ──────────────────────────────────────────┘└──
1315  end
st   ──┘
1316  
1317  theorem prim_iff {n f} : @primrec' n f ↔ primrec f := ⟨to_prim, of_prim⟩
id                             └──────┘    └─────┘      └─────┘  └─────┘
src                            └──────┘      └─────┘       └─────┘  └─────┘
typ                            └──────┘    └─────┘      └─────┘  └─────┘
doc                            └──────┘       └─────┘
1318  
1319  theorem prim_iff₁ {f : ℕ → ℕ} :
id                             
src                            
typ                            
1320    @primrec' 1 (λ v, f v.head) ↔ primrec f :=
id      └──────┘         └───┘   └─────┘ 
src     └──────┘            └───┘   └─────┘
typ     └──────┘         └───┘   └─────┘ 
doc     └──────┘                     └─────┘
1321  prim_iff.trans ⟨
id   └──────┘└────┘
src  └──────┘└────┘
typ  └──────┘└────┘
1322    λ h, (h.comp $ vector_of_fn $ λ i, primrec.id).of_eq (λ v, by simp),
id          └───┘   └──────────┘       └────────┘ └───┘     
src           └───┘   └──────────┘        └────────┘ └───┘           └──┘
typ         └───┘   └──────────┘       └────────┘ └───┘          └──┘
doc                                                                  └──┘
txt                                                                  └──┘
par                                                                  └──┘
st                                                                  └───┘
1323    λ h, h.comp vector_head⟩
id         └───┘ └─────────┘
src          └───┘ └─────────┘
typ        └───┘ └─────────┘
1324  
1325  theorem prim_iff₂ {f : ℕ → ℕ → ℕ} :
id                                
src                               
typ                               
1326    @primrec' 2 (λ v, f v.head v.tail.head) ↔ primrec₂ f :=
id      └──────┘         └───┘ └───┘└───┘   └──────┘ 
src     └──────┘            └───┘  └───┘└───┘   └──────┘
typ     └──────┘         └───┘ └───┘└───┘   └──────┘ 
doc     └──────┘                                 └──────┘
1327  prim_iff.trans ⟨
id   └──────┘└────┘
src  └──────┘└────┘
typ  └──────┘└────┘
1328    λ h, (h.comp $ vector_cons.comp fst $
id          └───┘   └─────────┘└───┘ └─┘
src           └───┘   └─────────┘└───┘ └─┘
typ         └───┘   └─────────┘└───┘ └─┘
1329      vector_cons.comp snd (primrec.const nil)).of_eq (λ v, by simp),
id       └─────────┘└───┘ └─┘  └───────────┘ └─┘  └───┘     
src      └─────────┘└───┘ └─┘  └───────────┘ └─┘  └───┘           └──┘
typ      └─────────┘└───┘ └─┘  └───────────┘ └─┘  └───┘          └──┘
doc                                                               └──┘
txt                                                               └──┘
par                                                               └──┘
st                                                               └───┘
1330    λ h, h.comp vector_head (vector_head.comp vector_tail)⟩
id         └───┘ └─────────┘  └─────────┘└───┘ └─────────┘
src          └───┘ └─────────┘  └─────────┘└───┘ └─────────┘
typ        └───┘ └─────────┘  └─────────┘└───┘ └─────────┘
1331  
1332  theorem vec_iff {m n f} :
1333    @vec m n f ↔ primrec f :=
id      └─┘     └─────┘ 
src     └─┘        └─────┘
typ     └─┘     └─────┘ 
doc                 └─────┘
1334  ⟨λ h, by simpa using vector_of_fn (λ i, to_prim (h i)),
id                       └──────────┘       └─────┘  
src           └──────────┘└──────────┘  └──┘└─────┘   └┘
typ          └──────────┘└──────────┘  └──┘└─────┘  └┘
doc           └──────────┘              └──┘          └┘
txt           └──────────┘              └──┘          └┘
par           └──────────┘              └──┘          └┘
pid                └────┘              └──┘          └┘
st           └────────────────────────────────────────────┘
1335   λ h i, of_prim $ vector_nth.comp h (primrec.const i)⟩
id         └─────┘   └────────┘└───┘   └───────────┘ 
src          └─────┘   └────────┘└───┘    └───────────┘
typ        └─────┘   └────────┘└───┘   └───────────┘ 
1336  
1337  end nat.primrec'
1338  
1339  theorem primrec.nat_sqrt : primrec nat.sqrt :=
id                              └─────┘ └──────┘
src                             └─────┘ └──────┘
typ                             └─────┘ └──────┘
doc                             └─────┘ └──────┘
1340  nat.primrec'.prim_iff₁.1 nat.primrec'.sqrt
id   └────────────────────┘  └───────────────┘
src  └────────────────────┘  └───────────────┘
typ  └────────────────────┘  └───────────────┘